大家好,第一发帖,小小紧张下。最近才开始学习内核,做了点笔记,有不足的地方也希望大家可以指出来,一起进步,谢谢。
#include <ntddk.h>
#define NTSTRSAFE_LIB
#include <ntstrsafe.h>
#ifndef SetFlag
#define SetFlag(_F,_SF) ((_F) |= (_SF))
#endif
#ifndef ClearFlag
#define ClearFlag(_F,_SF) ((_F) &= ~(_SF))
#endif
#define CCP_MAX_COM_ID 32
// 过滤设备和真实设备
static PDEVICE_OBJECT s_fltobj[CCP_MAX_COM_ID] = { 0 };
static PDEVICE_OBJECT s_nextobj[CCP_MAX_COM_ID] = { 0 };
// 打开一个端口设备
PDEVICE_OBJECT ccpOpenCom(ULONG id,NTSTATUS *status)
{
UNICODE_STRING name_str;
static WCHAR name[32] = { 0 };
//过滤设备对象指针
PFILE_OBJECT fileobj = NULL;
//过滤驱动对象指针
PDEVICE_OBJECT devobj = NULL;
// 输入字符串。
memset(name,0,sizeof(WCHAR)*32);
RtlStringCchPrintfW(
name,32,
L"\\Device\\Serial%d",id);
RtlInitUnicodeString(&name_str,name);
// 打开设备对象
//IoGetDeviceObjectPointer在知道名字的情况下,可以打开设备的指针
//返回文件对象fileobj和设备对象devobj。
*status = IoGetDeviceObjectPointer(&name_str, FILE_ALL_ACCESS, &fileobj, &devobj);
//打开了之后将文件对象接触引用。我们不需要
if (*status == STATUS_SUCCESS)
ObDereferenceObject(fileobj);
return devobj;
}
//NTSTATUS ccpAttachDevice
//传入driver和被绑定的的设备oldobj
//和需要初始化的绑定设备fltobj和绑定后的新地址*next
//函数完成后得到过滤设备设备对象fltobj和被绑定后的对象的设备栈最顶上对象的指针
//返回状态值
//绑定一个设备
NTSTATUS
ccpAttachDevice(
PDRIVER_OBJECT driver,
PDEVICE_OBJECT oldobj,
PDEVICE_OBJECT *fltobj,
PDEVICE_OBJECT *next)
{
NTSTATUS status;
//声明一个设备表示绑定后的最顶上设备的指针.
PDEVICE_OBJECT topdev = NULL;
// 生成设备,然后绑定之。
status = IoCreateDevice(driver, //DriverEntry的传入值
IN 0, //设备扩张 填0
IN NULL, //过滤设备名字,一般填NULL
IN oldobj->DeviceType, //生成的设备类型,与绑定的设备一致就好了
IN 0, //设备特征,一般先试0
IN FALSE,
OUT fltobj);//用于返回生成的设备
if (status != STATUS_SUCCESS) //生成失败 则返回失败值
return status;
// 拷贝重要标志位。
if(oldobj->Flags & DO_BUFFERED_IO)
(*fltobj)->Flags |= DO_BUFFERED_IO;
if(oldobj->Flags & DO_DIRECT_IO)
(*fltobj)->Flags |= DO_DIRECT_IO;
if(oldobj->Flags & DO_BUFFERED_IO)
(*fltobj)->Flags |= DO_BUFFERED_IO;
if(oldobj->Characteristics & FILE_DEVICE_SECURE_OPEN)
(*fltobj)->Characteristics |= FILE_DEVICE_SECURE_OPEN;
(*fltobj)->Flags |= DO_POWER_PAGABLE;
//生成过滤设备.绑定生成的设备到另一个设备上
// 绑定一个设备到另一个设备上
topdev = IoAttachDeviceToDeviceStack(*fltobj,oldobj);
//如果为NULL说明绑定失败了
if (topdev == NULL)
{
// 如果绑定失败了,销毁设备,重新来过。
IoDeleteDevice(*fltobj);
*fltobj = NULL;
status = STATUS_UNSUCCESSFUL;
return status;
}
*next = topdev; //一个设备指针指向绑定后的设备
// 设置这个设备已经启动。
(*fltobj)->Flags = (*fltobj)->Flags & ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
// 这个函数绑定所有的串口。
void ccpAttachAllComs(PDRIVER_OBJECT driver)
{
ULONG i;
PDEVICE_OBJECT com_ob;
NTSTATUS status;
for(i = 0;i<CCP_MAX_COM_ID;i++)
{
// 获得object引用。
com_ob = ccpOpenCom(i,&status);
if(com_ob == NULL)
continue;
// 在这里绑定。并不管绑定是否成功
//绑定之后,s_fltobj[i]是每个过滤驱动的地址的数组。而s_nextobj[i]是被绑定后的对象的设备栈最顶上对象的指针
ccpAttachDevice(driver,com_ob,&s_fltobj[i],&s_nextobj[i]);
// 取消object引用。
}
}
#define DELAY_ONE_MICROSECOND (-10)
#define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
#define DELAY_ONE_SECOND (DELAY_ONE_MILLISECOND*1000)
void ccpUnload(PDRIVER_OBJECT drv)
{
ULONG i;
LARGE_INTEGER interval;
// 首先解除绑定
for(i=0;i<CCP_MAX_COM_ID;i++)
{
if(s_nextobj[i] != NULL)
IoDetachDevice(s_nextobj[i]);
}
// 睡眠5秒。等待所有irp处理结束
interval.QuadPart = (5*1000 * DELAY_ONE_MILLISECOND);
KeDelayExecutionThread(KernelMode,FALSE,&interval);
// 删除这些设备
for(i=0;i<CCP_MAX_COM_ID;i++)
{
if(s_fltobj[i] != NULL)
IoDeleteDevice(s_fltobj[i]);
}
}
NTSTATUS ccpDispatch(PDEVICE_OBJECT device,PIRP irp)
{
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
NTSTATUS status;
ULONG i,j;
// 首先得知道发送给了哪个设备。设备一共最多CCP_MAX_COM_ID
// 个,是前面的代码保存好的,都在s_fltobj中。
for(i=0;i<CCP_MAX_COM_ID;i++)
{
if(s_fltobj[i] == device)
{
// 所有电源操作,全部直接放过。
if(irpsp->MajorFunction == IRP_MJ_POWER)
{
// 直接发送,然后返回说已经被处理了
PoStartNextPowerIrp(irp);
IoSkipCurrentIrpStackLocation(irp);
return PoCallDriver(s_nextobj[i],irp);
}
// 此外我们只过滤写请求。写请求的话,获得缓冲区以及其长度。
// 然后打印一下。
if(irpsp->MajorFunction == IRP_MJ_WRITE)
{
// 如果是写,先获得长度
ULONG len = irpsp->Parameters.Write.Length;
// 然后获得缓冲区
PUCHAR buf = NULL;
if(irp->MdlAddress != NULL)
buf =
(PUCHAR)
MmGetSystemAddressForMdlSafe(irp->MdlAddress,NormalPagePriority);
else
buf = (PUCHAR)irp->UserBuffer;
if(buf == NULL)
buf = (PUCHAR)irp->AssociatedIrp.SystemBuffer;
// 打印内容
for(j=0;j<len;++j)
{
DbgPrint("comcap: Send Data: %2x\r\n",
buf[j]);
}
}
// 这些请求直接下发执行即可。我们并不禁止或者改变它。
IoSkipCurrentIrpStackLocation(irp);
return IoCallDriver(s_nextobj[i],irp);
}
}
// 如果根本就不在被绑定的设备中,那是有问题的,直接返回参数错误。
irp->IoStatus.Information = 0;
irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
IoCompleteRequest(irp,IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
size_t i;
// 所有的分发函数都设置成一样的。
for(i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++)
{
driver->MajorFunction[i] = ccpDispatch;
}
// 支持动态卸载。
driver->DriverUnload = ccpUnload;
// 绑定所有的串口。
ccpAttachAllComs(driver);
// 直接返回成功即可。
return STATUS_SUCCESS;
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!