通常在WDM驱动的AddDevice里面只会调用一次IoCreateDevice创建一个设备对象。其实我们也可以调用多次IoCreateDevice来创建多个设备对象。当驱动调用IoCreateDevice成功后,驱动对象DriverObject的DeviceObject指针会指向新创建的设备对象,这个设备对象的NextDevice=NULL。如果再调用一次IoCreateDevice,那么DriverObject::DeviceObject指向新创建的设备对象,然后新创建的设备对象的NextDevice指向前面创建的设备对象。总体来讲,DriverObject::DeviceObject永远指向IoCreateDevice新创建的设备对象,而新创建的设备对象(DeviceObject::NextDevice)会指向前面一次创建的设备对象(如果没有,那么就是NULL)。
写个例子试试看,首先增加一个创建设备对象的函数:
NTSTATUS CreateFDO(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT pdo,
IN const wchar_t* pszDeviceName, IN const wchar_t* pszSymbolicLink)
{
NTSTATUS status;
PDEVICE_OBJECT fdo;
UNICODE_STRING devName;
RtlInitUnicodeString(&devName,pszDeviceName);//设备名称,设备名称只能被内核模式下的其他驱动所识别。
//创建FDO(Function Device Object)
status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION),
&(UNICODE_STRING)devName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&fdo);
if( !NT_SUCCESS(status))
return status;
KdPrint(("CreateFDO\n"));
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
pdx->fdo = fdo;
//将FDO附加在PDO上面,并且将Extension中的NextStackDevice指向FDO的下层设备。如果PDO上面有过滤驱动的话,NextStackDevice就是过滤驱动,如果没有就是PDO。
pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, pdo);
//创建一个缓冲,用来模拟文件。
pdx->buffer = (char*)ExAllocatePool(NonPagedPool, MAX_FILE_LEN);
pdx->filelen = 0;
//创建一个互斥对象
KeInitializeMutex(&pdx->myMutex, 0);
UNICODE_STRING symLinkName;
//创建链接符号,这样用户模式的应用就可以访问此设备。内核模式下,符号链接是以\??\开头的(或者\DosDevices\)。用户模式下则是\\.\开头。
//这里就可以在用户模式下用\\.\HelloWDM来访问本设备。
RtlInitUnicodeString(&symLinkName,pszSymbolicLink);
pdx->ustrDeviceName = devName;
pdx->ustrSymLinkName = symLinkName;
status = IoCreateSymbolicLink(&(UNICODE_STRING)symLinkName,&(UNICODE_STRING)devName);
if( !NT_SUCC