新建一个myhellodevice.c;
代码如下;makefile和sources如前文;
#include <ntddk.h>
#define NTDEVICE_NAME_STRING L"\\Device\\MytestDevice"
typedef struct _DEVICE_EXTENSION {
PDEVICE_OBJECT Self;
LIST_ENTRY EventQueueHead; // where all the user notification requests are queued
KSPIN_LOCK QueueLock;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
VOID DriverUnload(PDRIVER_OBJECT driver)
{
DbgPrint("goodbye");
}
// DriverEntry,入口函数。相当于main。
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
PDEVICE_OBJECT deviceObject;
UNICODE_STRING ntDeviceName;
UNICODE_STRING str1;
NTSTATUS status;
(void) RtlInitUnicodeString( &str1, L"my test str AAAA");
//DbgPrint(str1);
DbgPrint("%ws", str1.Buffer);
//创建设备对象
RtlInitUnicodeString(&ntDeviceName, NTDEVICE_NAME_STRING);
status = IoCreateDevice(driver, // DriverObject
sizeof(DEVICE_EXTENSION), // DeviceExtensionSize
&ntDeviceName, // DeviceName
FILE_DEVICE_UNKNOWN, // DeviceType
FILE_DEVICE_SECURE_OPEN, // DeviceCharacteristics
FALSE, // Not Exclusive
&deviceObject // DeviceObject
);
if (!NT_SUCCESS(status)) {
DbgPrint(("\tIoCreateDevice returned 0x%x\n", status));
return(status);
}
// 设置一个卸载函数便于这个函数能退出。
driver->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
驱动开发首先要了解的基本概念是驱动对象;然后就是设备对象;
DEVICE_OBJECT结构体是操作系统用来表示某个具体的设备对象,一个设备对象是一个逻辑上的,或者虚拟的,或者物理上的设备的具体抽象,驱动通过设备对象来处理I/O请求;
备对象用于保存设备特征和状态的相关信息。设备对象的I/O请求由一个驱动对象操控着。每一个内核模式的驱动必须创建设备对象,它通过调用IoCreateDevice函数一次或多次来创建。
设备对象用结构体DEVICE_OBJECT表示。每个设备对象有一个指针(NextDevice)指向下一个设备对象,从而形成一个设备对象链表。
在NT式驱动中创建设备对象是由IoCreateDevice内核函数完成的;
NTSTATUS IoCreateDevice{
IN PDRIVER_OBJECT DriverObject,
IN ULONG DeviceExtensionSize,
IN PUNICODE_STRING DeviceName OPTIONAL,
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharateristics,
OUT PDEVICE_OBJECT* DeviceObject
};
参数;
DriverObject:输入参数,每个驱动程序中,会有唯一的驱动对象与之对应
IoCreateDevice函数的第一个参数是本驱动的驱动对象;
DeviceExtensionSize:
输入参数,设备扩展的大小,
I/O管理器会根据这个大小,在内存中创建设备扩展,并与驱动对象关联;
DeviceName:
输入参数,设备对象的名字
DeviceCharacteristics:
输入参数,设置设备对象的特征
Exclusive:
输入参数,设置设备对象是否为内核模式下使用,一般为TRUE;
DeviceObject:
输入参数,I/O管理器负责创建这个设备对象,并返回设备对象的地址;
返回值:返回此函数的调用状态;
设备名称用UNICODE字符串指定,并且字符串必须是"\Device\[设备名]"的形式;
在windows下,所有设备都是以类似名字命名的;
例如C盘、D盘、E盘,以如下方式命名
"\Device\HarddiskVolume1" "\Device\HarddiskVolume2" "\Device\HarddiskVolume3"
也可以不指定不指定设备名字,如果是这样,
I/O管理器会自动分配一个数字作为设备的设备名,
例如"\Device\00000001" "\Device\00000002" "\Device\00000003"
若指定了设备名,只能被内核模式下的其他驱动所识别。但是在用户模式下的应用程序无法识别这个设备;
代码先来创建一个设备对象;看build是否成功;空闲再加载和调试;万一挂了,还有其他工作要做;
build成功;也许设备对象创建成功;但要完整运行,应该还有更多设备对象相关的代码;