IoCreateDevice 是驱动程序创建设备时需要调用的,通过阅读IoCreateDevice函数,可以更好理解设备对象和驱动对象的关系,以及设备对象的各种成员是如何起作用的。
windgb中显示DeviceObject的成员。
kd> dt nt!_device_object
+0x000 Type : Int2B
+0x002 Size : Uint2B
+0x004 ReferenceCount : Int4B
+0x008 DriverObject : Ptr32 _DRIVER_OBJECT
+0x00c NextDevice : Ptr32 _DEVICE_OBJECT
+0x010 AttachedDevice : Ptr32 _DEVICE_OBJECT
+0x014 CurrentIrp : Ptr32 _IRP
+0x018 Timer : Ptr32 _IO_TIMER
+0x01c Flags : Uint4B
+0x020 Characteristics : Uint4B
+0x024 Vpb : Ptr32 _VPB
+0x028 DeviceExtension : Ptr32 Void
+0x02c DeviceType : Uint4B
+0x030 StackSize : Char
+0x034 Queue : __unnamed
+0x05c AlignmentRequirement : Uint4B
+0x060 DeviceQueue : _KDEVICE_QUEUE
+0x074 Dpc : _KDPC
+0x094 ActiveThreadCount : Uint4B
+0x098 SecurityDescriptor : Ptr32 Void
+0x09c DeviceLock : _KEVENT
+0x0ac SectorSize : Uint2B
+0x0ae Spare1 : Uint2B
+0x0b0 DeviceObjectExtension : Ptr32 _DEVOBJ_EXTENSION
+0x0b4 Reserved : Ptr32 Void
该函数实现在 E:\Open_Source_Code\ReactOS\ntoskrnl\io\iomgr\device.c (E:\Open_Source_Code\ReactOS 保存ReactOS的源代码根目录)。原函数已经有必要的注释了。
NTSTATUS
NTAPI
IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
IN ULONG DeviceExtensionSize,
IN PUNICODE_STRING DeviceName,
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics,
IN BOOLEAN Exclusive,
OUT PDEVICE_OBJECT *DeviceObject)
{
WCHAR AutoNameBuffer[20];
UNICODE_STRING AutoName;
PDEVICE_OBJECT CreatedDeviceObject;
PDEVOBJ_EXTENSION DeviceObjectExtension;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
ULONG AlignedDeviceExtensionSize;
ULONG TotalSize;
HANDLE TempHandle;
PAGED_CODE();
/* Check if we have to generate a name */
if (DeviceCharacteristics & FILE_AUTOGENERATED_DEVICE_NAME)
{
/* Generate it 生成一个自动的设备名称 */
swprintf(AutoNameBuffer,
L"\\Device\\%08lx",
InterlockedIncrementUL(&IopDeviceObjectNumber));
/* Initialize the name */
RtlInitUnicodeString(&AutoName, AutoNameBuffer);
DeviceName = &AutoName;
}
/* Initialize the Object Attributes */
InitializeObjectAttributes(&ObjectAttributes,
DeviceName,
OBJ_KERNEL_HANDLE,
NULL,
SePublicOpenUnrestrictedSd);
/* Honor exclusive flag */
if (Exclusive) ObjectAttributes.Attributes |= OBJ_EXCLUSIVE;
/* Create a permanent object for named devices */
if (DeviceName) ObjectAttributes.Attributes |= OBJ_PERMANENT;
/* Align the Extension Size to 8-bytes 8字节对齐*/
AlignedDeviceExtensionSize = (DeviceExtensionSize + 7) &~ 7;
/* Total Size */
TotalSize = AlignedDeviceExtensionSize +
sizeof(DEVICE_OBJECT) +
sizeof(EXTENDED_DEVOBJ_EXTENSION);
/* Create the Device Object */
*DeviceObject = NULL;
Status = ObCreateObject(KernelMode,
IoDeviceObjectType,
&ObjectAttributes,
KernelMode,
NULL,
TotalSize,
0,
0,
(PVOID*)&CreatedDeviceObject);
if (!NT_SUCCESS(Status)) return Status;
/* Clear the whole Object and extension so we don't null stuff manually */
RtlZeroMemory(CreatedDeviceObject, TotalSize);
/*
* Setup the Type and Size. Note that we don't use the aligned size,
* because that's only padding for the DevObjExt and not part of the Object.
*/
CreatedDeviceObject->Type = IO_TYPE_DEVICE;
CreatedDeviceObject->Size = sizeof(DEVICE_OBJECT) + (USHORT)DeviceExtensionSize;
/* The kernel extension is after the driver internal extension */
DeviceObjectExtension = (PDEVOBJ_EXTENSION)
((ULONG_PTR)(CreatedDeviceObject + 1) +
AlignedDeviceExtensionSize);
/* Set the Type and Size. Question: why is Size 0 on Windows? */
DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION;
DeviceObjectExtension->Size = 0;
/* Initialize with Power Manager */
PoInitializeDeviceObject(DeviceObjectExtension);
/* Link the Object and Extension */
DeviceObjectExtension->DeviceObject = CreatedDeviceObject;
CreatedDeviceObject->DeviceObjectExtension = DeviceObjectExtension;
/* Set Device Object Data */
CreatedDeviceObject->DeviceType = DeviceType;
CreatedDeviceObject->Characteristics = DeviceCharacteristics;
CreatedDeviceObject->DeviceExtension = DeviceExtensionSize ?
CreatedDeviceObject + 1 :
NULL;
CreatedDeviceObject->StackSize = 1;
CreatedDeviceObject->AlignmentRequirement = 0;
/* Set the Flags */
CreatedDeviceObject->Flags = DO_DEVICE_INITIALIZING;
if (Exclusive) CreatedDeviceObject->Flags |= DO_EXCLUSIVE;
if (DeviceName) CreatedDeviceObject->Flags |= DO_DEVICE_HAS_NAME;
/* Attach a Vpb for Disks and Tapes, and create the Device Lock */
if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
(CreatedDeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK) ||
(CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) ||
(CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE))
{
/* Create Vpb */
Status = IopCreateVpb(CreatedDeviceObject);
if (!NT_SUCCESS(Status))
{
/* Dereference the device object and fail */
ObDereferenceObject(CreatedDeviceObject);
return Status;
}
/* Initialize Lock Event */
KeInitializeEvent(&CreatedDeviceObject->DeviceLock,
SynchronizationEvent,
TRUE);
}
/* Set the right Sector Size */
switch (DeviceType)
{
/* All disk systems */
case FILE_DEVICE_DISK_FILE_SYSTEM:
case FILE_DEVICE_DISK:
case FILE_DEVICE_VIRTUAL_DISK:
/* The default is 512 bytes */
CreatedDeviceObject->SectorSize = 512;
break;
/* CD-ROM file systems */
case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
/* The default is 2048 bytes */
CreatedDeviceObject->SectorSize = 2048;
}
/* Create the Device Queue */
if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
(CreatedDeviceObject->DeviceType == FILE_DEVICE_FILE_SYSTEM) ||
(CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) ||
(CreatedDeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) ||
(CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM))
{
/* Simple FS Devices, they don't need a real Device Queue */
InitializeListHead(&CreatedDeviceObject->Queue.ListEntry);
}
else
{
/* An actual Device, initialize its DQ */
KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue);
}
/* Insert the Object */
Status = ObInsertObject(CreatedDeviceObject,
NULL,
FILE_READ_DATA | FILE_WRITE_DATA,
1,
(PVOID*)&CreatedDeviceObject,
&TempHandle);
if (!NT_SUCCESS(Status)) return Status;
/* Now do the final linking */
ObReferenceObject(DriverObject);
ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0);
CreatedDeviceObject->DriverObject = DriverObject;
IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd);
/* Link with the power manager */
if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject);
/* Close the temporary handle and return to caller */
ObCloseHandle(TempHandle, KernelMode);
*DeviceObject = CreatedDeviceObject;
return STATUS_SUCCESS;
}