一个简单的NT驱动之创建设备对象函数(CreateDevice)

/****************************************************************

* 函数名称:CreateDrivce
* 功能描述:初始化设备对象
* 参数列表:
   pDriverObject:从I/O管理器中传进来的驱动对象
* 返回值:返回初始化状态

****************************************************************/
#pragma INITCODE

NTSTATUS CreateDeivce( 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;

//创建符号链接
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;
}

这个函数是在DriverEntry入口函数中执行的,该函数使用了5个数据类型,分别是PDRIVER_OBJECT、NTSTATUS、PDEVICE_OBJECT、PDEVICE_EXTENSION和UNICODE_STRING。其中PDRIVER_OBJECt是驱动对象,NTSTATUS是函数返回状态,PDEVICE_OBJECt是设备对象,PDEVICE_EXTENSION是头文件中自定义的一个结构体。该函数使用了四个内核函数,分别是RtlInitUnicodeString、IoCreateDevice、IoCreateSymbolicLink和IoDeleteDevice。

其中几个数据类型在第一篇笔记中差不多都已经谈到了,除了PDEVICE_EXTENSION这个结构体,该结构体定义的是设备对象扩展,其定义如下:

typedef struct _DEVICE_EXTENSION
{
PDEVICE_OBJECT pDevice;
UNICODE_STRING ustrDeviceName; //设备名称
UNICODE_STRING ustrSymLinkName; //符号链接名
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

该结构体只有三个成员,pDevice是设备对象,该成员的值由IoCreateDevice函数获得;ustrDeviceName是创建的设备名称;ustrSymLinkName是符号链接名。

接下来就是在驱动程序中第一次接触的几个内核函数,RtlInitUnicodeString函数是用来给UNICODE_STRING字符串赋值的;IoCreateDevice是用来创建设备对象的,在此有必要熟悉熟悉IoCreateDevice函数:

NTKERNELAPI
NTSTATUS
IoCreateDevice(
    __in PDRIVER_OBJECT DriverObject,
    __in ULONG DeviceExtensionSize,
    __in_opt PUNICODE_STRING DeviceName,
    __in DEVICE_TYPE DeviceType,
    __in ULONG DeviceCharacteristics,
    __in BOOLEAN Exclusive,
    __out
    __drv_out_deref(
        __drv_allocatesMem(Mem)
        __drv_when((((inFunctionClass$("DRIVER_INITIALIZE"))
             ||(inFunctionClass$("DRIVER_DISPATCH")))),
             __drv_aliasesMem)
        __on_failure(__null))
    PDEVICE_OBJECT *DeviceObject
    );

IoCreateDevice函数共有7个参数,包含6个输入函数和1个输出函数。其中DriverObject是驱动对象实例句柄;DeviceExtensionSize是自定义设备对象扩展的大小;DeviceName是设备对象名称,这个名称可以不设置,系统会自动为其命名;

DeviceType是一个比较重要的参数,该参数可以指定添加的驱动是即插即用设备还是非即插即用设备,对于非即插即用设备,应设置为FILE_DEVICE_UNKNOWN;DeviceCharacteristics为设置设备对象特征;Exclusive设置设备对象在内核模式下是否可用,一般为TRUE;最后一个参数是DeviceObject,该参数返回设备对象的地址。

现在要初始化设备对象扩展,在该扩展中指定当前设备对象的指针和设备对象名称,代码如下:

pDevObj->Flags |= DO_BUFFERED_IO;
pDevExt = ( PDEVICE_EXTENSION ) pDevObj->DeviceExtension;
pDevExt->pDevice = pDevObj;
pDevExt->ustrDeviceName = devName;

pDevObj为设备对象指针,“pDevObj->Flags |= DO_BUFFERED_IO;”是将设备设置为缓冲区设备,接着获取设备扩展指针赋值到pDevExt中,并设置设备对象扩展的设备对象及设备对象名称。

最后是创建符号链接,这如同给对象设备一个别名,以便记忆和识别。

//创建符号链接
UNICODE_STRING symLinkName;
RtlInitUnicodeString( &symLinkName, L"\\??\\HelloDDK" );
pDevExt->ustrSymLinkName = symLinkName;

status = IoCreateSymbolicLink( &symLinkName, &devName );
if ( !NT_SUCCESS( status ) )
{
   IoDeleteDevice( pDevObj );
   return status;
}

IoCreateSymbolicLink函数的第一个参数是符号链接名称,第二个参数是设备对象名称。

至此,DriverEntry入口函数中的功能均已实现,其大致顺序如下:

第一步:初始化驱动对象,设置IRP派遣函数和驱动卸载函数

第二步:创建设备对象。这一步可细分为创建设备对象、设置设备对象扩展、创建设备对象符号链接。

由于驱动程序对线程、硬件等的操作与文件操作类似,都包括打开、关闭、取消和退出等操作,所以也使用IO方式来进行控制,而在IRP派遣函数中就包含了这些特性。

在这第一个驱动程序中,只有一个IRP派遣函数,即HelloDDKDispatchRuntine,对于派遣函数的作用及设置将在另外一篇笔记中详细整理。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值