一个简单的NT驱动之驱动入口函数(DriverEntry)
2011年12月16日
选了本驱动开发方面的书《Windows驱动开发技术详解》,这本书类似于MFC方面孙鑫的《VC++深入详解》,看了一部分感觉还不错。
在开始看这本书之前查了许多资料,是想看看自己的实际需求需要看些哪方面的书,但发现要学的技术太多了,汇编要学,操作系统要学。还是不管了,先找本书来看看再说。
像学SDK时一样,照着书上的代码敲出了第一个驱动程序,称之为HelloDDK。
在开发驱动程序之前,有些概念是需要了解的,但我了解得不多,反正把环境架设好,可以写驱动程序了。首先在微软的官方网站上下载了WDK,许多资料中都是让装DDK,其实WDK只是DDK的升级版本而已,性质跟SDK一样,属于开发包之列。
这个驱动程序包含了三个函数:DriverEntry、HelloDDKUnload和HelloDDKDispatchRoutine。其中DriverEntry是驱动程序的入口函数,相当于C/C++程序的main函数,HelloDDKUnload函数是驱动卸载函数。而HelloDDKDispatchRuntine则是IRP的派遣函数,因为驱动程序主要是处理IO请求,而IO请求大多是在派遣函数中处理的。
先来看看这个驱动程序的第一个函数:DriverEntry
/****************************************************************
* 函数名称:DriverEntry
* 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
* 参数列表:
pDriverObject:从I/O管理器中传来的驱动对象
pRegistryPath:驱动程序在注册表中的路径
* 返回值:返回初始化驱动状态
****************************************************************/
#pragma INITCODE
extern "C" NTSTATUS DriverEntry( IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath )
{
NTSTATUS status;
KdPrint( ( "Enter DriverEntry!\n" ) );
//注册其它驱动调用函数入口
pDriverObject->DriverUnload = ( PDRIVER_UNLOAD ) HelloDDKUnload;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutine;
//创建驱动设备对象
status = CreateDeivce( pDriverObject );
KdPrint( ( "DriverEntry end!\n" ) );
return status;
}
这个函数的第一句代码是一个#pragma预处理指令:
#pragma INITCODE
这段代码表明将此函数加入INIT内存区域。
在函数头中的“extern "C"”是指定编译器的编译方式,若不加此修饰,编译器则会按C++的编译方式来编译,会导致编译错误。
NTSTATUS是函数的返回状态,用来检测函数的状态是否正确,常用的NTSTATUS值有:
#define STATUS_SUCCESS
#define STATUS_BUFFER_OVERFLOW
#define STATUS_UNSUCCESSFUL
#define STATUS_NOT_IMPLEMENTED
#define STATUS_ACCESS_VIOLATION
#define STATUS_INVALID_HANDLE
#define STATUS_INVALID_PARAMETER
接着是函数参数中的IN修饰,该修饰是定义参数的类型,“IN”修饰表示是一个输入参数,“OUT”修饰表示是一个输出参数,“INOUT”修饰表示是一个输入输出参数。
接下来就得了解了解驱动程序中的第一个结构体:PDRIVER_OBJECT,该结构体我在帮助文档里找了半天也没找到,最后在“wdm.h”中找到了其定义:
typedef struct _DRIVER_OBJECT {
CSHORT Type;
CSHORT Size;
PDEVICE_OBJECT DeviceObject;
ULONG Flags;
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
UNICODE_STRING DriverName;
PUNICODE_STRING HardwareDatabase;
PFAST_IO_DISPATCH FastIoDispatch;
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;
PDRIVER_UNLOAD DriverUnload;
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT;
typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT;
该结构体共有15个成员,这个结构体表示的是一个驱动对象,是驱动的一个实例,类似于用户模式下的线程句柄一类。该对象在DriverEntry函数中被始化,然后由内核中的I/O管理器来加载,确切的加载函数是IoCreateDevice。
下面要说说该结构体中的几个重要成员:
DeviceObject:这是一个设备对象的结构体。一个驱动程序会创建多个设备对象,每个设备对象都有指向下一个设备对象的指针,最后一个设备象的指针为空。此处的DeviceObject指向驱动程序的第一个设备对象,
DriverName:驱动名称。其数据类型为UNICODE_STRING,该字符串一般为“\\driver\\[驱动名称]”,UNICODE_STRING字符串的赋值用RtlInitUnicodeString函数。
DriverUnload:指定驱动卸载时使用的回调函数地址。
MajorFunction:该成员是一个PDRIVER_DISPATCH结构体组数指针,其定义如下:
__drv_functionClass(DRIVER_DISPATCH)
__drv_requiresIRQL(PASSIVE_LEVEL)
__drv_sameIRQL
typedef
NTSTATUS
DRIVER_DISPATCH (
__in struct _DEVICE_OBJECT *DeviceObject,
__inout struct _IRP *Irp
);
typedef DRIVER_DISPATCH *PDRIVER_DISPATCH;
每个指针指向一个函数,这个函数就是处理IRP的派遣函数。
FastIoDispatch:文件驱动中用到的派遣函数。
派遣函数相当于WIN32子系统下的事件响应函数,驱动程序的主要功能是负责处理IO请求,而绝大多数的IO请求是在派遣函数中处理的。关于IRP派遣函数的相关解释另作笔记。
在PDRIVER_OBJECT中有一个PDEVICE_OBJECT成员,下面再来说说这个结构体,其定义在“wdm.h”中。该结构体保存的是设备对象指针链表,其成员包含了当前设备对象指针和下一个设备对象指针。在卸载驱动时要遍历驱动程序的所有设备对象,并用IoDeleteDevice来删除所有设备对象。
好了,再来看看DriverEntry的函数体,在对以上的几个概念作了了解后,函数体的作用就容易理解了。函数体只有两个功能,一是初始化DRIVER_OBJECT结构体,二是创建设备对象。
糊里糊涂的写完了这篇笔记,没想一个只有十来行的驱动函数涉及的内容居然如此之多。虽然还是云里雾里的,但对驱动对象PDRIVER_OBJECT还是有了一点了解,在下一篇笔记中再来好好研究研究CreateDevice函数。
在敲这第一个驱动程序的代码时,老把Driver和Device敲错,到不是不知道这两个单词的意思,只是不知道在哪些地方该用驱动对象(DRIVER_OBJET),哪些地方用设备对象(DEVICE_OBJECT)。
发表评论
-
UNIX TCP/IP配置与检测
2012-01-20 10:31 866UNIX TCP/IP配置与检测 2010年12月14日 ... -
Web Application Stress Tool
2012-01-20 10:31 756Web Application Stress Tool 20 ... -
Jabberd2源代码分析:c2s与router SASL验证过程
2012-01-20 10:31 1456Jabberd2源代码分析:c2s与router SASL验证 ... -
VC中使用自定义消息在进程间通讯
2012-01-20 10:31 1124VC中使用自定义消息在进程间通讯 2011年06月14日 ... -
重叠IO 通信模型,函数记录。
2012-01-20 10:31 539重叠IO 通信模型,函数记录。 2010年12月07日 ... -
无法安装或运行此应用程序。该应用程序要求首先在“全局程序集缓存(GAC)”中安装程序集stdole版本7.0.3300.0
2012-01-19 15:31 2147无法安装或运行此应用程序。该应用程序要求首先在“全局程序集缓存 ... -
通用(任何android机型)Root教程(完整版!附砖机自救方法)转自安卓网
2012-01-19 15:31 2354通用(任何android机型)Root ... -
Android开发之--adb shell 命令大全
2012-01-19 15:31 674Android开发之--adb shell 命令大全 201 ... -
慢慢研究
2012-01-19 15:31 687慢慢研究 2011年12月24日 ... -
-微小说
2012-01-17 05:18 715-微小说 7 ... -
爱的人
2012-01-17 05:18 601爱的人 7小时前 感谢一路上有太多太多人的陪伴!又是一年 ... -
媳妇 你失眠 进来看看
2012-01-17 05:18 591媳妇 你失眠 进来看看 7小时前 不要问我为啥动这些 ... -
别忘记生命来时的样子…
2012-01-17 05:18 638别忘记生命来时的样子… 7小时前 每一个生命都像是被流放 ... -
106条心语语录――棠棠不落阁(写给青春一)
2012-01-17 05:18 699106条心语语录――棠棠 ... -
vs2005自带的水晶报表破解方法 (还没有试过)
2012-01-16 04:12 1287vs2005自带的水晶报表破解方法 (还没有试过) 2010 ... -
vs2005
2012-01-16 04:12 572vs2005 2010年06月06日 KYTYHTQKW ... -
vs2005 professional版注册码
2012-01-16 04:12 1277vs2005 professional版注册码 2009年1 ... -
ArcGIS Server 9.3 安装步骤及相关注意事项
2012-01-16 04:12 834ArcGIS Server 9.3 安装步骤及相关注意事项 ... -
ArcGIS Server 9.3 Net安装流程
2012-01-16 04:12 989ArcGIS Server 9.3 Net安装流程 2009 ...
相关推荐
驱动入口函数DriverEntry 入口函数参数DriverObject和RegistryPath B、书写SOURCES文件 C、书写makefile文件 D、用DDK-Build环境编译 1.3.2为DDK_HelloWorld添加卸载例程-10课 A、输出调试信息-KdPrint B、...
驱动程序同普通的 EXE,DLL一样,都属亍 PE文件,而且都有一个入口函数。但 EXE 中,入口函数是 main()/WinMain()和 Unicode的 wmain()/wWinmain(),DLL的入口函 数则可有可无,它是 DllMain()。驱动程序也有入口...
4.2.1 驱动加载过程与驱动入口函数(DriverEntry) 4.2.2 创建设备对象 4.2.3 DriverUnload例程 4.2.4 用WinObj观察驱动对象和设备对象 4.2.5 用DeviceTree观察驱动对象和设备对象 4.3 WDM式驱动的...
4.2.1 驱动加载过程与驱动入口函数(DriverEntry) 4.2.2 创建设备对象 4.2.3 DriverUnload例程 4.2.4 用WinObj观察驱动对象和设备对象 4.2.5 用DeviceTree观察驱动对象和设备对象 4.3 WDM式驱动的...
测试驱动程序 第一部分 一般内核模式 第1章Windows 2000和WDM驱动程序 第2章 分层的I/O、IRP和I/O对象 第3章 系统定义的对象和对驱动程序的支持 第4章 驱动程序基本结构 第5章DriverEntry 和 ...
9.3.2 Ramdisk驱动的入口函数 145 9.4 EvtDriverDeviceAdd函数 146 9.4.1 EvtDriverDeviceAdd的定义 146 9.4.2 局部变量的声明 146 9.4.3 磁盘设备的创建 147 9.4.4 如何处理发往设备的请求 148 9.4.5 用户...
3.1 NDIS微端口驱动程序入口函数 47 3.1.1 初始化包裹 47 3.1.2 注册微端口 48 3.1.2.1 指定NDIS版本号 48 3.1.2.2 注册MiniportXxx函数 48 3.1.2.3 为中断支持的注册处理程序 50 3.1.2.4 为无连接微端口选择一个...
9.3.2 Ramdisk驱动的入口函数 145 9.4 EvtDriverDeviceAdd函数 146 9.4.1 EvtDriverDeviceAdd的定义 146 9.4.2 局部变量的声明 146 9.4.3 磁盘设备的创建 147 9.4.4 如何处理发往设备的请求 148 9.4.5 用户...
4.7.5 驱动入口和卸载的实现 95 4.8 直接用端口操作键盘 96 4.8.1 读取键盘数据和命令端口 96 4.8.2 p2cUserFilter的最终实现 97 本章的示例代码 98 练习题 99 第5章 磁盘的虚拟 100 5.1 虚拟的磁盘 101 5.2 一个...
4.7.5 驱动入口和卸载的实现 95 4.8 直接用端口操作键盘 96 4.8.1 读取键盘数据和命令端口 96 4.8.2 p2cUserFilter的最终实现 97 本章的示例代码 98 练习题 99 第5章 磁盘的虚拟 100 5.1 虚拟的磁盘 101 5.2 一个...
4.7.5 驱动入口和卸载的实现 95 4.8 直接用端口操作键盘 96 4.8.1 读取键盘数据和命令端口 96 4.8.2 p2cUserFilter的最终实现 97 本章的示例代码 98 练习题 99 第5章 磁盘的虚拟 100 5.1 虚拟的磁盘 101 5.2 一个...
4.7.5 驱动入口和卸载的实现 95 4.8 直接用端口操作键盘 96 4.8.1 读取键盘数据和命令端口 96 4.8.2 p2cUserFilter的最终实现 97 本章的示例代码 98 练习题 99 第5章 磁盘的虚拟 100 5.1 虚拟的磁盘 101 5.2 一个...
4.7.5 驱动入口和卸载的实现 95 4.8 直接用端口操作键盘 96 4.8.1 读取键盘数据和命令端口 96 4.8.2 p2cUserFilter的最终实现 97 本章的示例代码 98 练习题 99 第5章 磁盘的虚拟 100 5.1 虚拟的磁盘 101 5.2 一个...
4.7.5 驱动入口和卸载的实现 95 4.8 直接用端口操作键盘 96 4.8.1 读取键盘数据和命令端口 96 4.8.2 p2cUserFilter的最终实现 97 本章的示例代码 98 练习题 99 第5章 磁盘的虚拟 100 5.1 虚拟的磁盘 101 5.2 一个...
4.7.5 驱动入口和卸载的实现 95 4.8 直接用端口操作键盘 96 4.8.1 读取键盘数据和命令端口 96 4.8.2 p2cUserFilter的最终实现 97 本章的示例代码 98 练习题 99 第5章 磁盘的虚拟 100 5.1 虚拟的磁盘 101 5.2 一个...
可以不用重起机子的方法,找一个动载加载驱动工具:DriverMonitor不错了。然后在“开始菜单”-> "运行"输入 "net start filedisk" 出现:“ 请求的服务已经启动”。这个必须得成功才行哦。 接下来注意点。cmd后 ...
2 FileDiskCreateDevice:调用IoCreateDevice创建设备,KeInitializeEvent初始化事件对象,PsCreateSystemThread创建内核线程,入口函数是FileDiskThread,传入的函数参数为IoCreateDevice返回的设备对象。...
驱动装载主入口函数 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath); 驱动卸载函数 VOID D1603Unload(PDRIVER_OBJECT DriverObject); 默认IRP回调函数 NTSTATUS D1603Dispatch...