/*
工作线程或者劳务线程,很重要,比起一般的内核线程。
它的运行环境不一般,在system中,特别是IRQL。
适用于小的任务,很方便。
made by correy
made at 2012.12.08
QQ:112426112
Email:kouleguan at hotmail dot com
Homepage:http://correy.webs.com
*/
#include <ntddk.h>
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
PDEVICE_OBJECT pdoNextDeviceObj = DriverObject->DeviceObject;//pdoGlobalDrvObj
//IoDeleteSymbolicLink(&usSymlinkName);//本程序没有创建符号链接。
while(pdoNextDeviceObj) // Delete all the device objects
{
PDEVICE_OBJECT pdoThisDeviceObj = pdoNextDeviceObj;
pdoNextDeviceObj = pdoThisDeviceObj->NextDevice;
IoDeleteDevice(pdoThisDeviceObj);
}
}
IO_WORKITEM_ROUTINE WorkItem;
VOID WorkItem(__in PDEVICE_OBJECT DeviceObject, __in_opt PVOID Context)
{//如果不是同步的,有可能在DriverEntry函数运行结束后才运行到这里。
DbgPrint("i am in WorkItem!\n");
KeSetEvent((PKEVENT)Context, 0, FALSE);
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
UNICODE_STRING usDeviceName;
PDEVICE_OBJECT pdoDeviceObj = 0;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PIO_WORKITEM g_piowi;
KEVENT g_ke;
KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint()
DriverObject->DriverUnload = OnUnload;
RtlInitUnicodeString(&usDeviceName, L"\\Device\\correy"); //必须创建设备,特别是Vista以前。
status = IoCreateDevice(DriverObject, 0, &usDeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pdoDeviceObj);
if(!NT_SUCCESS(status))
{
return status;
}
g_piowi = IoAllocateWorkItem(pdoDeviceObj); //参数是设备对象的指针,不是驱动对象的指针。不然WorkItem退出的时候,蓝屏。
if (g_piowi == 0)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
//IoInitializeWorkItem和IoAllocateWorkItem的功能差不多。
//If the caller will later pass the work item to IoQueueWorkItem, IoObject must point to a device object.
//IoInitializeWorkItem(DriverObject, &g_piowi);//Versions: Available on Windows Vista and later versions of Windows.
KeInitializeEvent(&g_ke, SynchronizationEvent, FALSE);//设置事件以便同步,也可以不同步。就多3行代码。
IoQueueWorkItem(g_piowi, &WorkItem, DelayedWorkQueue, &g_ke);
KeWaitForSingleObject(&g_ke, Executive,KernelMode, FALSE, NULL);
if (g_piowi)
{
IoFreeWorkItem(g_piowi);
}
return STATUS_SUCCESS;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
其实这个办法跟简单,没有和设备关联,而且暂时没有被软件废弃。
made by correy
made at 2012.08.13
Email:kouleguan at hotmail dot com
Homepage:http://correy.webs.com
*/
#include <ntifs.h>
#define TAG 'tset' //本驱动在内存中的标志,即test.
typedef struct WorkItemContext{
PWORK_QUEUE_ITEM Item;
HANDLE Pid;
}WorkItemContext;
PVOID allocate(IN SIZE_T NumberOfBytes)
{
PVOID p = NULL;
//PAGED_CODE();
if (KeGetCurrentIrql() > DISPATCH_LEVEL)
{
KdBreakPoint();//DbgBreakPoint()
}
/*
Callers of ExAllocatePoolWithTag must be executing at IRQL <= DISPATCH_LEVEL.
A caller executing at DISPATCH_LEVEL must specify a NonPagedXxx value for PoolType.
A caller executing at IRQL <= APC_LEVEL can specify any POOL_TYPE value, but the IRQL and environment must also be considered for determining the page type.
*/
p = ExAllocatePoolWithTag(NonPagedPool, NumberOfBytes, TAG);
if (p == NULL ) {
return p;
}
/*
Warning Memory that ExAllocatePoolWithTag allocates is uninitialized.
A kernel-mode driver must first zero this memory if it is going to make it visible to user-mode software (to avoid leaking potentially privileged contents).
*/
RtlZeroMemory(p, NumberOfBytes);
return p;
}
VOID free(IN PVOID p)
{
unsigned long r;
/*
Callers of ExFreePoolWithTag must be running at IRQL <= DISPATCH_LEVEL.
A caller at DISPATCH_LEVEL must have specified a NonPagedXxx PoolType when the memory was allocated.
Otherwise, the caller must be running at IRQL <= APC_LEVEL.
*/
//PAGED_CODE();
if (KeGetCurrentIrql() > DISPATCH_LEVEL)
{
KdBreakPoint();//DbgBreakPoint()
}
if (p) //防止多次释放导致的蓝屏。
{
__try //防止传入非法的地址。
{
r = MmIsAddressValid(p);
ExFreePoolWithTag(p, TAG);//KeGetCurrentIrql() > DISPATCH_LEVEL时依旧蓝屏。
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
r = GetExceptionCode();//啥也不做。
}
p = NULL;
}
}
VOID MY_PWORKER_THREAD_ROUTINE (IN PVOID Parameter)
{
WorkItemContext * pwic = (WorkItemContext *)Parameter;
//做一些事。
free(pwic->Item);
free(pwic);
}
DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
}
#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
WorkItemContext * wic;
KdBreakPoint();// == DbgBreakPoint()
DriverObject->DriverUnload = Unload;
//之所以采用结构是因为传递的参数不是一个(实际应用的也不是一个),并且不是同步控制的。
wic = (WorkItemContext *)allocate(sizeof(WorkItemContext));
if (wic == NULL) {
return status;
}
wic->Pid = 0;
wic->Item = (PWORK_QUEUE_ITEM)allocate(sizeof(WORK_QUEUE_ITEM));
if (wic->Item == NULL) {
free(wic);
return status;
}
ExInitializeWorkItem(wic->Item,MY_PWORKER_THREAD_ROUTINE,wic);
ExQueueWorkItem(wic->Item, DelayedWorkQueue);
return status;
}
没有评论:
发表评论