1)i/0定时器例程 每间隔1S 调用一次I/O定时器例程 可以定义初始值 为N 每次进入定时器例程 计数-- 就变化成 NS定时器
2)DPC例程 MS级别间隔,US级别间隔
I/O定时器 学习
NTSTATUS IoInitializeTimer( IN PDEVICE_OBJECT DeviceObject, //I/O定时器关联 设备对象指针 IN PIO_TIMER_ROUTINE TimerRoutine, //I/O定时器关联 定期例程 IN PVOID Context //传入定时器例程餐宿 );开启定时器:
VOID IoStartTimer( IN PDEVICE_OBJECT DeviceObject );停止I/O定时器:
VOID IoStopTimer( IN PDEVICE_OBJECT DeviceObject );
I/O定时器例程运行再 DISPATCH_LEVEL级别 不能使用分页内存
(Windows NT使用了分页文件Pagefile.sys。为了运行不同的进程和应用程序,Pagefile.sys给物理内存分配了一些空间。在这些空间内允许交换数据页。 )
示例:
1)初始化 定时器
IoInitializeTimer(pDevObj,OnTimer,NULL);
2)设备扩展中加入 计数变量 负责记录间隔秒数
LONG lTimerCount;
3)定义两个IOCTL码 IOCTL_START_TIMER + IOCTL_STOP
当应用程序发起这两个IOCTL请求后,开启+关闭定时器
00000000 0.00000000 Enter DriverEntry 00000001 0.00008241 Leave DriverEntry 00000002 6.68917799 Enter HelloDDKDispatchRoutin 00000003 6.68918133 IRP_MJ_CREATE 00000004 6.68969822 Leave HelloDDKDispatchRoutin 00000005 6.69020081 Enter HelloDDKDeviceIOControl 00000006 6.69020319 IOCTL_START_TIMER 00000007 6.69070101 Leave HelloDDKDeviceIOControl 00000008 7.63543415 Enter OnTimer! ////////////////////////////////// 00000009 7.63543749 previousCount = 2 //初始化为3 不停-- 00000010 7.63543987 TIMER_OUT = 3 00000011 7.63544321 The current process is Idle 00000012 8.63506699 Enter OnTimer! 00000013 8.63507080 previousCount = 1 00000014 8.63507271 TIMER_OUT = 3 00000015 8.63507652 The current process is Idle 00000016 9.63517284 Enter OnTimer! 00000017 9.63517666 previousCount = 0 00000018 9.63517857 TIMER_OUT = 3 00000019 9.63518238 3 seconds time out! 00000020 9.63518429 The current process is Idle 00000021 10.63625240 Enter OnTimer! 00000022 10.63712025 previousCount = 2 00000023 10.63813972 TIMER_OUT = 3 00000024 10.63814354 The current process is vmtoolsd.exe 00000025 11.63535500 Enter OnTimer! 00000026 11.63535786 previousCount = 1 00000027 11.63536072 TIMER_OUT = 3 00000028 11.63536358 The current process is Idle 00000029 12.63484955 Enter OnTimer! 00000030 12.63485241 previousCount = 0 00000031 12.63485527 TIMER_OUT = 3 00000032 12.63485718 3 seconds time out! 00000033 12.63486099 The current process is Idle 00000034 13.63495541 Enter OnTimer! 00000035 13.63495827 previousCount = 2 00000036 13.63496113 TIMER_OUT = 3 00000037 13.63496399 The current process is Idle 00000038 14.63765812 Enter OnTimer! 00000039 14.63766193 previousCount = 1 00000040 14.63766384 TIMER_OUT = 3 00000041 14.63766670 The current process is Idle 00000042 15.63519192 Enter OnTimer! 00000043 15.63519955 previousCount = 0 00000044 15.63520241 TIMER_OUT = 3 00000045 15.63520622 3 seconds time out! 00000046 15.63520908 The current process is irptrace.exe 00000047 16.63495064 Enter OnTimer! 00000048 16.63495255 previousCount = 2 00000049 16.63495636 TIMER_OUT = 3 00000050 16.63495827 The current process is Idle 00000051 16.69157982 Enter HelloDDKDeviceIOControl 00000052 16.69165039 IOCTL_STOP 00000053 16.69217110 Leave HelloDDKDeviceIOControl 00000054 16.69274902 Enter HelloDDKDispatchRoutin 00000055 16.69275093 IRP_MJ_CLEANUP 00000056 16.69323921 Leave HelloDDKDispatchRoutin 00000057 16.69375610 Enter HelloDDKDispatchRoutin 00000058 16.69375801 IRP_MJ_CLOSE 00000059 16.69423866 Leave HelloDDKDispatchRoutin
驱动代码:
#include "Driver.h" #pragma INITCODE extern "C" NTSTATUS DriverEntry ( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath ) { NTSTATUS status; KdPrint(("Enter DriverEntry ")); //设置卸载函数 pDriverObject->DriverUnload = HelloDDKUnload; //设置派遣函数 for (int i = 0; i < arraysize(pDriverObject->MajorFunction); ++i) pDriverObject->MajorFunction[i] = HelloDDKDispatchRoutin; pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDeviceIOControl; //创建驱动设备对象 status = CreateDevice(pDriverObject); KdPrint(("Leave DriverEntry ")); return status; } #pragma LOCKEDCODE //不能使用分页内存 运行再DISPATCH_LEVEL的IRQL级别 VOID OnTimer( IN PDEVICE_OBJECT DeviceObject, IN PVOID Context) { PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; KdPrint(("Enter OnTimer! ")); //将计数器自锁减一 InterlockedDecrement(&pDevExt->lTimerCount); //如果计数器减到0,重新编程TIMER_OUT,整个过程是互锁运算 LONG previousCount = InterlockedCompareExchange(&pDevExt->lTimerCount,TIMER_OUT,0);//3秒 KdPrint(("previousCount = %d ",previousCount)); KdPrint(("TIMER_OUT = %d ",TIMER_OUT)); //每隔三秒,计数器一个循环,输出以下log if (previousCount==0) { KdPrint(("%d seconds time out! ",TIMER_OUT)); } //证明该线程运行在任意线程上下文的 PEPROCESS pEProcess = IoGetCurrentProcess(); PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);//即可得到用户进程 KdPrint(("The current process is %s ",ProcessName)); //为了证明该线程能运行再任意线程上下文 输处线程名称 } /************************************************************************ * 函数名称:CreateDevice * 功能描述:初始化设备对象 * 参数列表: pDriverObject:从I/O管理器中传进来的驱动对象 * 返回 值:返回初始化状态 *************************************************************************/ #pragma INITCODE NTSTATUS CreateDevice ( IN PDRIVER_OBJECT pDriverObject) { NTSTATUS status; PDEVICE_OBJECT pDevObj; PDEVICE_EXTENSION pDevExt; //创建设备名称 UNICODE_STRING devName; RtlInitUnicodeString(&devName,L"\Device\MyDDKDevice"); //创建设备 status = IoCreateDevice( pDriverObject, sizeof(DEVICE_EXTENSION), &(UNICODE_STRING)devName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj ); if (!NT_SUCCESS(status)) return status; pDevObj->Flags |= DO_DIRECT_IO; pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension; pDevExt->pDevice = pDevObj; pDevExt->ustrDeviceName = devName; IoInitializeTimer(pDevObj,OnTimer,NULL); //创建符号链接 UNICODE_STRING symLinkName; RtlInitUnicodeString(&symLinkName,L"\??\HelloDDK"); pDevExt->ustrSymLinkName = symLinkName; status = IoCreateSymbolicLink( &symLinkName,&devName ); if (!NT_SUCCESS(status)) { IoDeleteDevice( pDevObj ); return status; } return STATUS_SUCCESS; } /************************************************************************ * 函数名称:HelloDDKUnload * 功能描述:负责驱动程序的卸载操作 * 参数列表: pDriverObject:驱动对象 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) { PDEVICE_OBJECT pNextObj; KdPrint(("Enter DriverUnload ")); pNextObj = pDriverObject->DeviceObject; while (pNextObj != NULL) { PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) pNextObj->DeviceExtension; //删除符号链接 UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName; IoDeleteSymbolicLink(&pLinkName); pNextObj = pNextObj->NextDevice; IoDeleteDevice( pDevExt->pDevice ); } } /************************************************************************ * 函数名称:HelloDDKDispatchRoutin * 功能描述:对读IRP进行处理 * 参数列表: pDevObj:功能设备对象 pIrp:从IO请求包 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { KdPrint(("Enter HelloDDKDispatchRoutin ")); PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp); //建立一个字符串数组与IRP类型对应起来 static char* irpname[] = { "IRP_MJ_CREATE", "IRP_MJ_CREATE_NAMED_PIPE", "IRP_MJ_CLOSE", "IRP_MJ_READ", "IRP_MJ_WRITE", "IRP_MJ_QUERY_INFORMATION", "IRP_MJ_SET_INFORMATION", "IRP_MJ_QUERY_EA", "IRP_MJ_SET_EA", "IRP_MJ_FLUSH_BUFFERS", "IRP_MJ_QUERY_VOLUME_INFORMATION", "IRP_MJ_SET_VOLUME_INFORMATION", "IRP_MJ_DIRECTORY_CONTROL", "IRP_MJ_FILE_SYSTEM_CONTROL", "IRP_MJ_DEVICE_CONTROL", "IRP_MJ_INTERNAL_DEVICE_CONTROL", "IRP_MJ_SHUTDOWN", "IRP_MJ_LOCK_CONTROL", "IRP_MJ_CLEANUP", "IRP_MJ_CREATE_MAILSLOT", "IRP_MJ_QUERY_SECURITY", "IRP_MJ_SET_SECURITY", "IRP_MJ_POWER", "IRP_MJ_SYSTEM_CONTROL", "IRP_MJ_DEVICE_CHANGE", "IRP_MJ_QUERY_QUOTA", "IRP_MJ_SET_QUOTA", "IRP_MJ_PNP", }; UCHAR type = stack->MajorFunction; if (type >= arraysize(irpname)) KdPrint((" - Unknown IRP, major type %X ", type)); else KdPrint((" %s ", irpname[type])); NTSTATUS status = STATUS_SUCCESS; // 完成IRP pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("Leave HelloDDKDispatchRoutin ")); return status; } #pragma PAGEDCODE NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; KdPrint(("Enter HelloDDKDeviceIOControl ")); //得到当前堆栈 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp); //得到输入缓冲区大小 ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength; //得到输出缓冲区大小 ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength; //得到IOCTL码 ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) pDevObj->DeviceExtension; ULONG info = 0; switch (code) { // process request case IOCTL_START_TIMER: { KdPrint(("IOCTL_START_TIMER ")); pDevExt->lTimerCount = TIMER_OUT; IoStartTimer(pDevObj); break; } case IOCTL_STOP: { KdPrint(("IOCTL_STOP ")); IoStopTimer(pDevObj); break; } default: status = STATUS_INVALID_VARIANT; } // 完成IRP pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = info; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("Leave HelloDDKDeviceIOControl ")); return status; }应用程序代码:
#include <windows.h>
#include <stdio.h>
//使用CTL_CODE必须加入winioctl.h
#include <winioctl.h>
#include "..NT_DriverIoctls.h"
int main()
{
HANDLE hDevice =
CreateFile("\\.\HelloDDK",
GENERIC_READ | GENERIC_WRITE,
0, // share mode none
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL ); // no template
if (hDevice == INVALID_HANDLE_VALUE)
{
printf("Failed to obtain file handle to device: "
"%s with Win32 error code: %d
",
"MyWDMDevice", GetLastError() );
return 1;
}
DWORD dwOutput;
DeviceIoControl(hDevice, IOCTL_START_TIMER, NULL, 0, NULL, 0, &dwOutput, NULL);//IOCTL_START_TIMER 这个是自定义的
Sleep(10000);
DeviceIoControl(hDevice, IOCTL_STOP, NULL, 0, NULL, 0, &dwOutput, NULL);
CloseHandle(hDevice);
return 0;
}
IDLE 和 系统进程一样 都是一种特殊进程,没有响应的EXE文件与之对应
DPC定时器学习
更加灵活 任意间断时间使用DPC定时器
使用KTIMER对象 当对定时器设置一个时间间隔后,每隔这段时间 系统将一个DPC例程插入DPC队列,当系统读取DPC队列时,对应DPC例程会被执行
初始化 定时器 对象:
VOID KeInitializeTimer( IN PKTIMER Timer //定时器指针 );
初始化 DPC 对象:
VOID KeInitializeDpc( IN PRKDPC Dpc, //初始化的DPC对象指针 IN PKDEFERRED_ROUTINE DeferredRoutine, //与DPC关联的DPC例程 每当定时器间隔到时,操作系统就会将一个DPC对象插入队列 触发该例程 IN PVOID DeferredContext //传入DPC例程的参数 );开启定时器:
BOOLEAN KeSetTimer( //在调用KeSetTimer 后,只会触发一次DPC例程,如果想周期的触发DPC例程,需要在DPC例程被触发后 再次调用KeSetTimer IN PKTIMER Timer, //定时器对象指针 IN LARGE_INTEGER DueTime, //时间间隔 如果它是正数,绝对时间,负数 则意味着 间隔多长时间,时间单位 100NS IN PKDPC Dpc OPTIONAL //传入DPC例程参数 );取消定时器:
BOOLEAN KeCancelTimer( IN PKTIMER Timer );示例:
1)定义两个 IOCTL -》开启+关闭定时器
2)在传递IOCTL_START_TIMER时,将间隔的时间 从应用程序 传递到驱动程序,这样时间间隔是由应用程序控制的
应用程序中调用DeviceIOControl 让驱动程序开启定时器 + 关闭定时器,并告诉定时器间隔时间
DeviceIoControl(hDevice, IOCTL_START_TIMER, &dwMircoSeconds, sizeof(DWORD), NULL, 0, &dwOutput, NULL); Sleep(10000); DeviceIoControl(hDevice, IOCTL_STOP_TIMER, NULL, 0, NULL, 0, &dwOutput, NULL);
3)设备扩展中加入 DPC对象 + 定时器对象
KDPC pollingDPC; // 存储DPC对象 KTIMER pollingTimer;// 存储计时器对象 LARGE_INTEGER pollingInterval; // 记录计时器间隔时间4)初始化 DPC对象时,需要将设备对象作为参数传递给DPC例程。这样在DPC例程中可以通过设备对象 指针获得间隔时间,时间记录在设备扩展中
KeInitializeTimer( &pDevExt->pollingTimer ); KeInitializeDpc( &pDevExt->pollingDPC, PollingTimerDpc, //例程函数 (PVOID) pDevObj );5)在IRP_MJ_DEVICE_CONTROL 的派遣函数 中,接受 IOCTL_START_TIMER后,可以将应用程序传递进来的间隔时间记录下来
调用KeSetTimer函数开启 定时器 在接受 IOCTL_STOP_TIMER后,调用 KeCancelTimer函数停止定时器
#include "Driver.h" #pragma INITCODE extern "C" NTSTATUS DriverEntry ( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath ) { NTSTATUS status; KdPrint(("Enter DriverEntry ")); //设置卸载函数 pDriverObject->DriverUnload = HelloDDKUnload; //设置派遣函数 for (int i = 0; i < arraysize(pDriverObject->MajorFunction); ++i) pDriverObject->MajorFunction[i] = HelloDDKDispatchRoutin; pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDeviceIOControl; //创建驱动设备对象 status = CreateDevice(pDriverObject); KdPrint(("Leave DriverEntry ")); return status; } #pragma LOCKEDCODE VOID PollingTimerDpc( IN PKDPC pDpc, //////////////////////////////////////////// IN PVOID pContext, IN PVOID SysArg1, IN PVOID SysArg2 ) { PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext; PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension; KeSetTimer( //只会触发一次 DPC例程,需要重新开启 &pdx->pollingTimer, pdx->pollingInterval, //每隔 一段 时间久执行一次 直到 应用程序 传递 STOP IRP 过来 &pdx->pollingDPC ); KdPrint(("PollingTimerDpc ")); //检验是运行在任意线程上下文 PEPROCESS pEProcess = IoGetCurrentProcess(); PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174); KdPrint(("%s ",ProcessName)); } /************************************************************************ * 函数名称:CreateDevice * 功能描述:初始化设备对象 * 参数列表: pDriverObject:从I/O管理器中传进来的驱动对象 * 返回 值:返回初始化状态 *************************************************************************/ #pragma INITCODE NTSTATUS CreateDevice ( IN PDRIVER_OBJECT pDriverObject) { NTSTATUS status; PDEVICE_OBJECT pDevObj; PDEVICE_EXTENSION pDevExt; //创建设备名称 UNICODE_STRING devName; RtlInitUnicodeString(&devName,L"\Device\MyDDKDevice"); //创建设备 status = IoCreateDevice( pDriverObject, sizeof(DEVICE_EXTENSION), &(UNICODE_STRING)devName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj ); if (!NT_SUCCESS(status)) return status; pDevObj->Flags |= DO_DIRECT_IO; pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension; pDevExt->pDevice = pDevObj; pDevExt->ustrDeviceName = devName; KeInitializeTimer( &pDevExt->pollingTimer ); ////////////////////////////////// KeInitializeDpc( &pDevExt->pollingDPC, PollingTimerDpc, (PVOID) pDevObj ); /////////////////////////////////// //创建符号链接 UNICODE_STRING symLinkName; RtlInitUnicodeString(&symLinkName,L"\??\HelloDDK"); pDevExt->ustrSymLinkName = symLinkName; status = IoCreateSymbolicLink( &symLinkName,&devName ); if (!NT_SUCCESS(status)) { IoDeleteDevice( pDevObj ); return status; } return STATUS_SUCCESS; } /************************************************************************ * 函数名称:HelloDDKUnload * 功能描述:负责驱动程序的卸载操作 * 参数列表: pDriverObject:驱动对象 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) { PDEVICE_OBJECT pNextObj; KdPrint(("Enter DriverUnload ")); pNextObj = pDriverObject->DeviceObject; while (pNextObj != NULL) { PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) pNextObj->DeviceExtension; //删除符号链接 UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName; IoDeleteSymbolicLink(&pLinkName); pNextObj = pNextObj->NextDevice; IoDeleteDevice( pDevExt->pDevice ); } } /************************************************************************ * 函数名称:HelloDDKDispatchRoutin * 功能描述:对读IRP进行处理 * 参数列表: pDevObj:功能设备对象 pIrp:从IO请求包 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { KdPrint(("Enter HelloDDKDispatchRoutin ")); PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp); //建立一个字符串数组与IRP类型对应起来 static char* irpname[] = { "IRP_MJ_CREATE", "IRP_MJ_CREATE_NAMED_PIPE", "IRP_MJ_CLOSE", "IRP_MJ_READ", "IRP_MJ_WRITE", "IRP_MJ_QUERY_INFORMATION", "IRP_MJ_SET_INFORMATION", "IRP_MJ_QUERY_EA", "IRP_MJ_SET_EA", "IRP_MJ_FLUSH_BUFFERS", "IRP_MJ_QUERY_VOLUME_INFORMATION", "IRP_MJ_SET_VOLUME_INFORMATION", "IRP_MJ_DIRECTORY_CONTROL", "IRP_MJ_FILE_SYSTEM_CONTROL", "IRP_MJ_DEVICE_CONTROL", "IRP_MJ_INTERNAL_DEVICE_CONTROL", "IRP_MJ_SHUTDOWN", "IRP_MJ_LOCK_CONTROL", "IRP_MJ_CLEANUP", "IRP_MJ_CREATE_MAILSLOT", "IRP_MJ_QUERY_SECURITY", "IRP_MJ_SET_SECURITY", "IRP_MJ_POWER", "IRP_MJ_SYSTEM_CONTROL", "IRP_MJ_DEVICE_CHANGE", "IRP_MJ_QUERY_QUOTA", "IRP_MJ_SET_QUOTA", "IRP_MJ_PNP", }; UCHAR type = stack->MajorFunction; if (type >= arraysize(irpname)) KdPrint((" - Unknown IRP, major type %X ", type)); else KdPrint((" %s ", irpname[type])); NTSTATUS status = STATUS_SUCCESS; // 完成IRP pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("Leave HelloDDKDispatchRoutin ")); return status; } #pragma PAGEDCODE NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; KdPrint(("Enter HelloDDKDeviceIOControl ")); //得到当前堆栈 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp); //得到输入缓冲区大小 ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength; //得到输出缓冲区大小 ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength; //得到IOCTL码 ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) pDevObj->DeviceExtension; ULONG info = 0; switch (code) { // process request case IOCTL_START_TIMER: { KdPrint(("IOCTL_START_TIMER! ")); //从用户模式传进来的超时 ULONG ulMircoSeconds = *(PULONG)pIrp->AssociatedIrp.SystemBuffer; //记录应用程序传递过来的 间隔时间 pDevExt->pollingInterval = RtlConvertLongToLargeInteger( ulMircoSeconds * -10 );//时间单位是 100纳秒 KeSetTimer( &pDevExt->pollingTimer, pDevExt->pollingInterval, &pDevExt->pollingDPC ); break; } case IOCTL_STOP_TIMER: { KdPrint(("IOCTL_STOP_TIMER! ")); KeCancelTimer(&pDevExt->pollingTimer); break; } default: status = STATUS_INVALID_VARIANT; } // 完成IRP pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = info; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("Leave HelloDDKDeviceIOControl ")); return status; }应用程序:
#include <windows.h> #include <stdio.h> //使用CTL_CODE必须加入winioctl.h #include <winioctl.h> #include "..NT_DriverIoctls.h" int main() { HANDLE hDevice = CreateFile("\\.\HelloDDK", GENERIC_READ | GENERIC_WRITE, 0, // share mode none NULL, // no security OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); // no template if (hDevice == INVALID_HANDLE_VALUE) { printf("Failed to obtain file handle to device: " "%s with Win32 error code: %d ", "MyWDMDevice", GetLastError() ); return 1; } DWORD dwOutput; DWORD dwMircoSeconds = 1000*1000*1; DeviceIoControl(hDevice, IOCTL_START_TIMER, &dwMircoSeconds, sizeof(DWORD), NULL, 0, &dwOutput, NULL); Sleep(10000); DeviceIoControl(hDevice, IOCTL_STOP_TIMER, NULL, 0, NULL, 0, &dwOutput, NULL); CloseHandle(hDevice); return 0; }
等待学习:
1)KeWaitForSingleObject
NTSTATUS KeWaitForSingleObject( //等待内核同步对象 IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL );
#pragma PAGEDCODE VOID WaitMicroSecond1(ULONG ulMircoSecond) { KEVENT kEvent; KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond)); //初始化一个未激发的内核事件 KeInitializeEvent(&kEvent,SynchronizationEvent,FALSE); //等待时间的单位是100纳秒,将微秒转换成这个单位 //负数代表是从此刻到未来的某个时刻 LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMircoSecond); //在经过timeout后,线程继续运行 KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, &timeout); KdPrint(("Thread is running again! ")); }2)使用 KeDelayExecutionThread
NTSTATUS KeDelayExecutionThread( //强制当前线程进入 睡眠状态 经过睡眠时间后,线程恢复运行 IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Interval );
#pragma PAGEDCODE VOID WaitMicroSecond2(ULONG ulMircoSecond) { KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond)); //等待时间的单位是100纳秒,将微秒转换成这个单位 //负数代表是从此刻到未来的某个时刻 LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMircoSecond); //此种方法类似于KeWaitForSingleObject //将当前线程进入睡眠状态,间隔时间到转入运行状态 KeDelayExecutionThread(KernelMode,FALSE,&timeout); KdPrint(("Thread is running again! ")); }3)KeStallExecutionProcessor
VOID KeStallExecutionProcessor( //让CPU处于忙等待状态,而不是处于睡眠。经过指定时间后,继续让线程运行 不宜超过50US IN ULONG MicroSeconds );1 000 000 US = 1S
#pragma PAGEDCODE VOID WaitMicroSecond3(ULONG ulMircoSecond) { KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond)); //忙等待,此种方法属于忙等待,比较浪费CPU时间 //因此使用该方法不宜超过50微秒 KeStallExecutionProcessor(ulMircoSecond); KdPrint(("Thread is running again! ")); }4)使用定时器
#pragma PAGEDCODE VOID WaitMicroSecond4(ULONG ulMircoSecond) { //使用计时器 这里没有使用DPC例程 + 对象 KTIMER kTimer;//内核计时器 //初始化计时器 KeInitializeTimer(&kTimer); LARGE_INTEGER timeout = RtlConvertLongToLargeInteger( ulMircoSecond * -10 ); //注意这个计时器没有和DPC对象关联 KeSetTimer(&kTimer,timeout, NULL); //第三个参数 没有设置 DPC例程 就没有DPC例程 KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond)); KeWaitForSingleObject(&kTimer,Executive,KernelMode,FALSE,NULL); KdPrint(("Thread is running again! ")); }
#include "Driver.h" #pragma INITCODE extern "C" NTSTATUS DriverEntry ( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath ) { NTSTATUS status; KdPrint(("Enter DriverEntry ")); //设置卸载函数 pDriverObject->DriverUnload = HelloDDKUnload; //设置派遣函数 for (int i = 0; i < arraysize(pDriverObject->MajorFunction); ++i) pDriverObject->MajorFunction[i] = HelloDDKDispatchRoutin; pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDeviceIOControl; //创建驱动设备对象 status = CreateDevice(pDriverObject); KdPrint(("Leave DriverEntry ")); return status; } /************************************************************************ * 函数名称:CreateDevice * 功能描述:初始化设备对象 * 参数列表: pDriverObject:从I/O管理器中传进来的驱动对象 * 返回 值:返回初始化状态 *************************************************************************/ #pragma INITCODE NTSTATUS CreateDevice ( IN PDRIVER_OBJECT pDriverObject) { NTSTATUS status; PDEVICE_OBJECT pDevObj; PDEVICE_EXTENSION pDevExt; //创建设备名称 UNICODE_STRING devName; RtlInitUnicodeString(&devName,L"\Device\MyDDKDevice"); //创建设备 status = IoCreateDevice( pDriverObject, sizeof(DEVICE_EXTENSION), &(UNICODE_STRING)devName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj ); if (!NT_SUCCESS(status)) return status; pDevObj->Flags |= DO_DIRECT_IO; pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension; pDevExt->pDevice = pDevObj; pDevExt->ustrDeviceName = devName; //创建符号链接 UNICODE_STRING symLinkName; RtlInitUnicodeString(&symLinkName,L"\??\HelloDDK"); pDevExt->ustrSymLinkName = symLinkName; status = IoCreateSymbolicLink( &symLinkName,&devName ); if (!NT_SUCCESS(status)) { IoDeleteDevice( pDevObj ); return status; } return STATUS_SUCCESS; } /************************************************************************ * 函数名称:HelloDDKUnload * 功能描述:负责驱动程序的卸载操作 * 参数列表: pDriverObject:驱动对象 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) { PDEVICE_OBJECT pNextObj; KdPrint(("Enter DriverUnload ")); pNextObj = pDriverObject->DeviceObject; while (pNextObj != NULL) { PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) pNextObj->DeviceExtension; //删除符号链接 UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName; IoDeleteSymbolicLink(&pLinkName); pNextObj = pNextObj->NextDevice; IoDeleteDevice( pDevExt->pDevice ); } } /************************************************************************ * 函数名称:HelloDDKDispatchRoutin * 功能描述:对读IRP进行处理 * 参数列表: pDevObj:功能设备对象 pIrp:从IO请求包 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { KdPrint(("Enter HelloDDKDispatchRoutin ")); PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp); //建立一个字符串数组与IRP类型对应起来 static char* irpname[] = { "IRP_MJ_CREATE", "IRP_MJ_CREATE_NAMED_PIPE", "IRP_MJ_CLOSE", "IRP_MJ_READ", "IRP_MJ_WRITE", "IRP_MJ_QUERY_INFORMATION", "IRP_MJ_SET_INFORMATION", "IRP_MJ_QUERY_EA", "IRP_MJ_SET_EA", "IRP_MJ_FLUSH_BUFFERS", "IRP_MJ_QUERY_VOLUME_INFORMATION", "IRP_MJ_SET_VOLUME_INFORMATION", "IRP_MJ_DIRECTORY_CONTROL", "IRP_MJ_FILE_SYSTEM_CONTROL", "IRP_MJ_DEVICE_CONTROL", "IRP_MJ_INTERNAL_DEVICE_CONTROL", "IRP_MJ_SHUTDOWN", "IRP_MJ_LOCK_CONTROL", "IRP_MJ_CLEANUP", "IRP_MJ_CREATE_MAILSLOT", "IRP_MJ_QUERY_SECURITY", "IRP_MJ_SET_SECURITY", "IRP_MJ_POWER", "IRP_MJ_SYSTEM_CONTROL", "IRP_MJ_DEVICE_CHANGE", "IRP_MJ_QUERY_QUOTA", "IRP_MJ_SET_QUOTA", "IRP_MJ_PNP", }; UCHAR type = stack->MajorFunction; if (type >= arraysize(irpname)) KdPrint((" - Unknown IRP, major type %X ", type)); else KdPrint((" %s ", irpname[type])); NTSTATUS status = STATUS_SUCCESS; // 完成IRP pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("Leave HelloDDKDispatchRoutin ")); return status; } #pragma PAGEDCODE VOID WaitMicroSecond1(ULONG ulMircoSecond) { KEVENT kEvent; KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond)); //初始化一个未激发的内核事件 KeInitializeEvent(&kEvent,SynchronizationEvent,FALSE); //等待时间的单位是100纳秒,将微秒转换成这个单位 //负数代表是从此刻到未来的某个时刻 LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMircoSecond); //在经过timeout后,线程继续运行 KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, &timeout); KdPrint(("Thread is running again! ")); } #pragma PAGEDCODE VOID WaitMicroSecond2(ULONG ulMircoSecond) { KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond)); //等待时间的单位是100纳秒,将微秒转换成这个单位 //负数代表是从此刻到未来的某个时刻 LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMircoSecond); //此种方法类似于KeWaitForSingleObject //将当前线程进入睡眠状态,间隔时间到转入运行状态 KeDelayExecutionThread(KernelMode,FALSE,&timeout); KdPrint(("Thread is running again! ")); } #pragma PAGEDCODE VOID WaitMicroSecond3(ULONG ulMircoSecond) { KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond)); //忙等待,此种方法属于忙等待,比较浪费CPU时间 //因此使用该方法不宜超过50微秒 KeStallExecutionProcessor(ulMircoSecond); KdPrint(("Thread is running again! ")); } #pragma PAGEDCODE VOID WaitMicroSecond4(ULONG ulMircoSecond) { //使用计时器 KTIMER kTimer;//内核计时器 //初始化计时器 KeInitializeTimer(&kTimer); LARGE_INTEGER timeout = RtlConvertLongToLargeInteger( ulMircoSecond * -10 ); //注意这个计时器没有和DPC对象关联 KeSetTimer(&kTimer,timeout, NULL); KdPrint(("Thread suspends %d MircoSeconds...",ulMircoSecond)); KeWaitForSingleObject(&kTimer,Executive,KernelMode,FALSE,NULL); KdPrint(("Thread is running again! ")); } #pragma PAGEDCODE NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; KdPrint(("Enter HelloDDKDeviceIOControl ")); //得到当前堆栈 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp); //得到输入缓冲区大小 ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength; //得到输出缓冲区大小 ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength; //得到IOCTL码 ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) pDevObj->DeviceExtension; ULONG info = 0; //得到用户程序传进来的微秒数 ULONG ulMircoSecond = *(PULONG)pIrp->AssociatedIrp.SystemBuffer; switch (code) { // process request case IOCTL_WAIT_METHOD1: { KdPrint(("IOCTL_WAIT_METHOD1 ")); WaitMicroSecond1(ulMircoSecond); break; } case IOCTL_WAIT_METHOD2: { KdPrint(("IOCTL_WAIT_METHOD2 ")); WaitMicroSecond2(ulMircoSecond); break; } case IOCTL_WAIT_METHOD3: { KdPrint(("IOCTL_WAIT_METHOD3 ")); WaitMicroSecond3(ulMircoSecond); break; } case IOCTL_WAIT_METHOD4: { KdPrint(("IOCTL_WAIT_METHOD4 ")); WaitMicroSecond4(ulMircoSecond); break; } default: status = STATUS_INVALID_VARIANT; } // 完成IRP pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = info; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("Leave HelloDDKDeviceIOControl ")); return status; }
VOID KeQuerySystemTime( //单位时间为100NS OUT PLARGE_INTEGER CurrentTime //返回当前系统时间 );
VOID ExSystemTimeToLocalTime( //将系统时间转换为当前时区对应的时间 IN PLARGE_INTEGER SystemTime, //输入系统时间 OUT PLARGE_INTEGER LocalTime //返回当前时区时间 );
VOID ExLocalTimeToSystemTime( IN PLARGE_INTEGER LocalTime, //输入当前时区时间 OUT PLARGE_INTEGER SystemTime //返回系统时间 );
BOOLEAN RtlTimeFieldsToTime( //由当前的年月日 得到系统时间 IN PTIME_FIELDS TimeFields, //输入的年月日 IN PLARGE_INTEGER Time //输出转换的系统时间 );
typedef struct TIME_FIELDS { CSHORT Year; //1601 CSHORT Month; //1-12 CSHORT Day; CSHORT Hour; CSHORT Minute; CSHORT Second; CSHORT Milliseconds; CSHORT Weekday; } TIME_FIELDS;
VOID RtlTimeToTimeFields( //将系统时间 -》 年月日等信息 IN PLARGE_INTEGER Time, IN PTIME_FIELDS TimeFields );示例:
#pragma PAGEDCODE VOID Time_Test() { LARGE_INTEGER current_system_time; //得到当前系统时间 KeQuerySystemTime(¤t_system_time); LARGE_INTEGER current_local_time; //从系统时间转换成当地时区时间 ExSystemTimeToLocalTime(¤t_system_time,¤t_local_time); TIME_FIELDS current_time_info; //由当地时区时间得到月日年信息 RtlTimeToTimeFields(¤t_local_time,¤t_time_info); //显示年月日等信息 KdPrint(("Current year:%d ",current_time_info.Year)); KdPrint(("Current month:%d ",current_time_info.Month)); KdPrint(("Current day:%d ",current_time_info.Day)); KdPrint(("Current Hour:%d ",current_time_info.Hour)); KdPrint(("Current Minute:%d ",current_time_info.Minute)); KdPrint(("Current Second:%d ",current_time_info.Second)); KdPrint(("Current Milliseconds:%d ",current_time_info.Milliseconds)); KdPrint(("Current Weekday:%d ",current_time_info.Weekday)); } #pragma PAGEDCODE NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; KdPrint(("Enter HelloDDKDeviceIOControl ")); //得到当前堆栈 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp); //得到输入缓冲区大小 ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength; //得到输出缓冲区大小 ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength; //得到IOCTL码 ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) pDevObj->DeviceExtension; ULONG info = 0; switch (code) { // process request case IOCTL_TIME_TEST: { KdPrint(("IOCTL_TIME_TEST ")); Time_Test(); break; } default: status = STATUS_INVALID_VARIANT; } // 完成IRP pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = info; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("Leave HelloDDKDeviceIOControl ")); return status; }
int main() { HANDLE hDevice = CreateFile("\\.\HelloDDK", GENERIC_READ | GENERIC_WRITE, 0, // share mode none NULL, // no security OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); // no template if (hDevice == INVALID_HANDLE_VALUE) { printf("Failed to obtain file handle to device: " "%s with Win32 error code: %d ", "MyWDMDevice", GetLastError() ); return 1; } DWORD dwOutput; DeviceIoControl(hDevice, IOCTL_TIME_TEST, NULL, 0, NULL, 0, &dwOutput, NULL); CloseHandle(hDevice); return 0; }
IRP的 超时 处理:
由于硬件设备,IRP 传递到底层驱动程序后 不能及时处理,甚至可能永远不被处理,这时需要超时情况来处理
在应用程序中 CancelIO Win32 API 函数 或者 在驱动程序中执行 IoCancelIRP 内核函数
也可以设置IRP超时, IRP超时后,操作系统会取消IRP,从而进入IRP的取消例程
示例:
1)初始化一个定时器对象 + DPC对象 ,将DPC例程 和 定时器对象进行关联
2)在每次对IRP操作前,开启定时器,设置好一定的超时
3)如果在指定时间内对IRP的处理没有结束,那么操作系统会进入DPC例程
4)这里演示IRP_MJ_READ 返回 PENDING IRP不会结束
5)本例子 超时 3S ,在处理超时的DPC例程中,IRP被强制结束
00000001 8.88969421 Enter DriverEntry 00000002 8.88976192 Leave DriverEntry 00000003 22.56484413 Enter HelloDDKDispatchRoutin 00000004 22.56485367 IRP_MJ_CREATE 00000005 22.56535339 Leave HelloDDKDispatchRoutin 00000006 22.56587219 Enter HelloDDKRead 00000007 22.56587982 Leave HelloDDKRead 00000008 25.56596184 Cancel the current pending irp! 00000009 25.56675720 Enter HelloDDKRead 00000010 25.56677437 Leave HelloDDKRead 00000011 28.56680679 Cancel the current pending irp! 00000012 28.61609268 Enter HelloDDKDispatchRoutin 00000013 28.61609459 IRP_MJ_CLEANUP 00000014 28.61660194 Leave HelloDDKDispatchRoutin 00000015 28.61712837 Enter HelloDDKDispatchRoutin 00000016 28.61713028 IRP_MJ_CLOSE 00000017 28.61759949 Leave HelloDDKDispatchRoutin 00000018 34.55936050 Enter DriverUnload
#include "Driver.h" #pragma INITCODE extern "C" NTSTATUS DriverEntry ( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath ) { NTSTATUS status; KdPrint(("Enter DriverEntry ")); //设置卸载函数 pDriverObject->DriverUnload = HelloDDKUnload; //设置派遣函数 pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutin; pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutin; pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutin; pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKRead; pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = HelloDDKDispatchRoutin; pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDispatchRoutin; pDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = HelloDDKDispatchRoutin; pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = HelloDDKDispatchRoutin; pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HelloDDKDispatchRoutin; //创建驱动设备对象 status = CreateDevice(pDriverObject); KdPrint(("Leave DriverEntry ")); return status; } #pragma LOCKEDCODE VOID OnTimerDpc( IN PKDPC pDpc, IN PVOID pContext, IN PVOID SysArg1, IN PVOID SysArg2 ) { PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext; PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension; PIRP currentPendingIRP = pdx->currentPendingIRP; KdPrint(("Cancel the current pending irp! ")); //设置完成状态为STATUS_CANCELLED currentPendingIRP->IoStatus.Status = STATUS_CANCELLED; currentPendingIRP->IoStatus.Information = 0; // bytes xfered IoCompleteRequest( currentPendingIRP, IO_NO_INCREMENT ); } /************************************************************************ * 函数名称:CreateDevice * 功能描述:初始化设备对象 * 参数列表: pDriverObject:从I/O管理器中传进来的驱动对象 * 返回 值:返回初始化状态 *************************************************************************/ #pragma INITCODE NTSTATUS CreateDevice ( IN PDRIVER_OBJECT pDriverObject) { NTSTATUS status; PDEVICE_OBJECT pDevObj; PDEVICE_EXTENSION pDevExt; //创建设备名称 UNICODE_STRING devName; RtlInitUnicodeString(&devName,L"\Device\MyDDKDevice"); //创建设备 status = IoCreateDevice( pDriverObject, sizeof(DEVICE_EXTENSION), &(UNICODE_STRING)devName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj ); if (!NT_SUCCESS(status)) return status; pDevObj->Flags |= DO_BUFFERED_IO; pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension; pDevExt->pDevice = pDevObj; pDevExt->ustrDeviceName = devName; KeInitializeTimer( &pDevExt->pollingTimer ); KeInitializeDpc( &pDevExt->pollingDPC, OnTimerDpc, (PVOID) pDevObj ); //创建符号链接 UNICODE_STRING symLinkName; RtlInitUnicodeString(&symLinkName,L"\??\HelloDDK"); pDevExt->ustrSymLinkName = symLinkName; status = IoCreateSymbolicLink( &symLinkName,&devName ); if (!NT_SUCCESS(status)) { IoDeleteDevice( pDevObj ); return status; } return STATUS_SUCCESS; } /************************************************************************ * 函数名称:HelloDDKUnload * 功能描述:负责驱动程序的卸载操作 * 参数列表: pDriverObject:驱动对象 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) { PDEVICE_OBJECT pNextObj; KdPrint(("Enter DriverUnload ")); pNextObj = pDriverObject->DeviceObject; while (pNextObj != NULL) { PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) pNextObj->DeviceExtension; //删除符号链接 UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName; IoDeleteSymbolicLink(&pLinkName); pNextObj = pNextObj->NextDevice; IoDeleteDevice( pDevExt->pDevice ); } } /************************************************************************ * 函数名称:HelloDDKDispatchRoutin * 功能描述:对读IRP进行处理 * 参数列表: pDevObj:功能设备对象 pIrp:从IO请求包 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { KdPrint(("Enter HelloDDKDispatchRoutin ")); PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp); //建立一个字符串数组与IRP类型对应起来 static char* irpname[] = { "IRP_MJ_CREATE", "IRP_MJ_CREATE_NAMED_PIPE", "IRP_MJ_CLOSE", "IRP_MJ_READ", "IRP_MJ_WRITE", "IRP_MJ_QUERY_INFORMATION", "IRP_MJ_SET_INFORMATION", "IRP_MJ_QUERY_EA", "IRP_MJ_SET_EA", "IRP_MJ_FLUSH_BUFFERS", "IRP_MJ_QUERY_VOLUME_INFORMATION", "IRP_MJ_SET_VOLUME_INFORMATION", "IRP_MJ_DIRECTORY_CONTROL", "IRP_MJ_FILE_SYSTEM_CONTROL", "IRP_MJ_DEVICE_CONTROL", "IRP_MJ_INTERNAL_DEVICE_CONTROL", "IRP_MJ_SHUTDOWN", "IRP_MJ_LOCK_CONTROL", "IRP_MJ_CLEANUP", "IRP_MJ_CREATE_MAILSLOT", "IRP_MJ_QUERY_SECURITY", "IRP_MJ_SET_SECURITY", "IRP_MJ_POWER", "IRP_MJ_SYSTEM_CONTROL", "IRP_MJ_DEVICE_CHANGE", "IRP_MJ_QUERY_QUOTA", "IRP_MJ_SET_QUOTA", "IRP_MJ_PNP", }; UCHAR type = stack->MajorFunction; if (type >= arraysize(irpname)) KdPrint((" - Unknown IRP, major type %X ", type)); else KdPrint((" %s ", irpname[type])); //对一般IRP的简单操作,后面会介绍对IRP更复杂的操作 NTSTATUS status = STATUS_SUCCESS; // 完成IRP pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("Leave HelloDDKDispatchRoutin ")); return status; } NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { KdPrint(("Enter HelloDDKRead ")); PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) pDevObj->DeviceExtension; //将IRP设置为挂起 IoMarkIrpPending(pIrp); //将挂起的IRP记录下来 pDevExt->currentPendingIRP = pIrp; //定义3秒的超时 ULONG ulMicroSecond = 3000000; //将32位整数转化成64位整数 LARGE_INTEGER timeout = RtlConvertLongToLargeInteger(-10*ulMicroSecond); KeSetTimer( &pDevExt->pollingTimer, timeout, &pDevExt->pollingDPC ); KdPrint(("Leave HelloDDKRead ")); //返回pending状态 return STATUS_PENDING; }