章一.从两个最简单的驱动谈起

以下内容全部来自《Windows驱动开发技术详解》,作者张帆、史彩成等,属摘抄型笔记。

///

1.Windows驱动程序分为两类:一类是不支持即插即用功能的NT式驱动;另一类是这hi吃即插即用功能的WDM式驱动。


2.NT式驱动程序需要导入的头文件是NTDDK.h;WDM式驱动程序要导入的头文件是WDM.h。


3.DriverFrame.h文件及解释

#pragma once

#include <NTDDK.h>  //NT式驱动开发必须的头文件NTDDK.h


/************************************************************************************/
/* Windows 驱动开发中,所有程序的函数和变量都要指明被加载到分页内存中还是非分页内存中
   DriverEntry函数需要放在INIT标志的内存中
   INIT标志指明该函数只是在加载时需要载入内存,加载成功后即可从内存中卸载           */                                                               
/************************************************************************************/
#define PAGECODE code_seg("PAGE")  //分页内存标记
#define LOCKCODE code_seg()        //非分页内存标记
#define INITCODE code_seg("INIT")  //初始化内存块

#define PAGEDATA data_seg("PAGE")
#define LOCKDATA data_seg()
#define INITDATA data_seg("INIT")

#define ArraySize(p) (sizeof(p)/sizeof((p)[0]))

//一个设备拓展结构体,根据不同驱动程序的需要,负责补充定义设备的相关信息
typedef struct _DEVICE_EXTENSION
{
	PDEVICE_OBJECT pDevice;
	UNICODE_STRING ustrDeviceName;  //设备名
	UNICODE_STRING ustrSymLinkName; //符号链接名
} DEVICE_EXTENSION, * PDEVICE_EXTENSION; //设备拓展结构


//函数声明
NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject);    //创建设备
VOID FrameUnload(IN PDRIVER_OBJECT pDriverObject);         //驱动卸载
NTSTATUS FrameDispatch(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp);  

4.驱动入口函数DriverEntry

#include "DriverFrame.h"

//指明此函数加载到INIT内存区域中,即成功卸载后,可以退出内存
#pragma INITCODE

/***********************************************************************
	Windows驱动程序的入口函数不是main函数,而是一个叫做DriverEntry的函数
	由内核中的I/O管理器负责调用
***********************************************************************/


/***********************************************************************
	函数名称:DriverEntry
    功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
    参数列表:
			pDriverObject:从I/O管理器中传递进来的驱动对象
			pRegPath:驱动程序在注册表中的路径
	返回值:返回初始化驱动状态                                            
***********************************************************************/
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegPath)
{
	NTSTATUS status = STATUS_SUCCESS;
	//打印调试信息,在调试版本中使用DbgPrint进行调试信息输出,在发行版本中,不执行任何操作
	/***********************************************************************
	#if DBG
	#define KdPrint(_x_) DbgPrint _x_
	#else
	#define KdPrint(_x_)                    
	***********************************************************************/
	KdPrint(("Enter DriverEntry\n"));

	//注册其他驱动调用函数入口
	//驱动向I/O管理器注册一些回调函数,由操作系统负责调用
	pDriverObject->DriverUnload = FrameUnload;
	//驱动处理创建、读写、关闭相关IRP时,调用FrameDispatch
	pDriverObject->MajorFunction[IRP_MJ_CREATE] = FrameDispatch;
	pDriverObject->MajorFunction[IRP_MJ_WRITE] = FrameDispatch;
	pDriverObject->MajorFunction[IRP_MJ_READ] = FrameDispatch;	
	pDriverObject->MajorFunction[IRP_MJ_CLOSE] = FrameDispatch;
	
	//创建驱动设备对象
	status = CreateDevice(pDriverObject);

	KdPrint(("DriverEntry End\n"));
	return status;	
}


5.创建设备对象函数CreateDevice

/***********************************************************************
	函数名称:CreateDevice
	功能描述:初始化设备对象
	参数列表:
			pDriverObject:从I/O管理器中传递进来的驱动对象
	返回值:返回初始化状态
***********************************************************************/
#pragma INITCODE
NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject)
{
	NTSTATUS status = STATUS_SUCCESS;
	PDEVICE_OBJECT pDeviceObject;
	PDEVICE_EXTENSION pDeviceExt;

	//创建设备名称
	//构造一个UNICODE字符串,保存设备对象名称
	UNICODE_STRING devName;
	UNICODE_STRING symLinkName;
	RtlInitUnicodeString(&devName, L"\\Device\\DriverFrameDevice");
	RtlInitUnicodeString(&symLinkName, L"\\??\\DriverFrame");

	//使用IoCreateDevice创建一个设备对象
	//设备对象类型为FILE_DEVICE_UNKNOWN,独占设备,只能被一个应用程序使用
	status = IoCreateDevice(pDriverObject, sizeof(PDEVICE_EXTENSION), 
							&devName, FILE_DEVICE_UNKNOWN,
							0, TRUE, &pDeviceObject);
	if ( !NT_SUCCESS(status) )
	{
		return status;
	}

	pDeviceObject->Flags |= DO_BUFFERED_IO;
	pDeviceExt = (PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;
	pDeviceExt->pDevice = pDeviceObject;
	pDeviceExt->ustrDeviceName = devName;

	//创建符号链接
	//驱动程序虽然有了设备名称,但是这种设备名称只能在内核态可见
	//需要暴露一个符号链接,指向真正的设备名
	
	
	pDeviceExt->ustrSymLinkName = symLinkName;
	status = IoCreateSymbolicLink(&symLinkName, &devName);
	if ( !NT_SUCCESS(status) )
	{
		IoDeleteDevice(pDeviceObject);
		return status;
	}
	return STATUS_SUCCESS;
}



6.驱动卸载函数FrameUnload

/***********************************************************************                                                                      
	函数名:FrameUnload
	功能描述:负责驱动程序的卸载操作
	参数列表:
			pDriverObject:驱动对象
	返回值:无
	PS:驱动被卸载时由I/O管理器负责调用此回调函数
***********************************************************************/
#pragma PAGECODE
VOID FrameUnload(IN PDRIVER_OBJECT pDriverObject)
{
	PDEVICE_OBJECT pNextDev;
	KdPrint(("Enter FrameUnload\r\n"));

	//由驱动对象得到设备对象
	pNextDev = pDriverObject->DeviceObject;
	//遍历驱动的所有设备对象,并进行删除
	while (pNextDev != NULL)
	{
		PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pNextDev->DeviceExtension;

		//删除设备对象符号链接
		UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
		IoDeleteSymbolicLink(&pLinkName);

		pNextDev = pNextDev->NextDevice;
		IoDeleteDevice(pDevExt->pDevice);
	}
}



7.默认派遣例程FrameDispatch

/***********************************************************************
	函数名称:FrameDispatch
	功能描述:对IRP进行处理
	参数列表:
			pDeviceObject:功能设备对象
			pIrp:从I/O请求包
	返回值:返回状态
	PS:由于是最简单的驱动框架,所以不做任何事情
***********************************************************************/
#pragma PAGECODE
NTSTATUS FrameDispatch(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;

	KdPrint(("Enter FrameDispatch\n"));

	//设置IRP的状态为成功
	pIrp->IoStatus.Status = status;

	//设置操作的字节数为0
	pIrp->IoStatus.Information = 0;

	//指示完成此IRP
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	KdPrint(("FrameDispatch End\n"));
	return status;
}


8.使用DDK/WDK环境编译驱动程序

在源文件目录下新建两个无后缀名文本文件,分别命名为makefile和sources

a.markfile文件可以从其他驱动例子程序中拷贝,无需修改,主要内容如下:

!INCLUDE $(NTMAKEENV)\makefile.def
b.sources文件则标识了编译时的一些信息,内容如下:

TARGETNAME=DRIVERFRAME
TARGETTYPE=DRIVER
TARGETPATH=OBJ

INCLUDES=$(BASEDIR)\inc;\
         $(BASEDIR)\inc\ddk;\

SOURCES=DriverFrame.c\
都是自解释的比较好理解,就不一一注释。

c.通过DDK/WDK的命令行进入到源文件所在目录,使用build命令进行编译,即可生成相关驱动及PDB文件。



9.驱动的安装

书中介绍了一种安装方式,但是已经有前人写了非常好用的工具,直接在虚拟机内安装观察是否产生问题即可。至于安装工具后续会继续学习。


PS:至于书中写道VC6下的编译,个人觉得没有必要,将VC作为一个编辑器比较合适,在命令行下编译能看到更多的信息。如果之后有需要使用VC/VS环境,再回头复习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目录 第1篇 入门篇 第1章 从两个简单驱动谈起 1.1 DDK的安装 1.2 第一个驱动程序HelloDDK的代码分析 1.2.1 HelloDDK的头文件 1.2.2 HelloDDK的入口函数 1.2.3 创建设备例程 1.2.4 卸载驱动例程 1.2.5 默认派遣例程 1.3 HelloDDK的编译和安装 1.3.1 用DDK环境编译HelloDDK 1.3.2 用VC集成开发环境编译HelloDDK 1.3.3 HelloDDK的安装 1.4 第二个驱动程序HelloWDM的代码分析 1.4.1 HelloWDM的头文件 1.4.2 HelloWDM的入口函数 1.4.3 HelloWDM的AddDevice例程 1.4.4 HelloWDM处理PNP的回调函数 1.4.5 HelloWDM对PNP的默认处理 1.4.6 HelloWDM对IRP_MN_REMOVE_DEVICE的处理 1.4.7 HelloWDM对其他IRP的回调函数 1.4.8 HelloWDM的卸载例程 1.5 HelloWDM的编译和安装 1.5.1 用DDK编译环境编译HelloWDM 1.5.2 HelloWDM的编译过程 1.5.3 安装HelloWDM 1.6 小结 第2章 Windows操作驱动的基本概念 第3章 Windows驱动编译环境配置、安装及调试 第4章 驱动程序的基本结构 第5章 Windows内存管理 第6章 Windows内核函数 第7章 派遣函数 第2篇 进阶篇 第8章 驱动程序的同步处理 第9章 IRP的同步 第10章 定时器 第11章 驱动程序调用驱动程序 第12章 分层驱动程序 第13章 让设备实现即插即用 第14章 电源管理 第3篇 实用篇 第15章 I/O端口操作 第16章 PCI设备驱动 第17章 USB设备驱动 第18章 SDIO设备驱动 第19章 虚拟串口设备驱动 第20章 摄像头设备驱动程序 第4篇 提高篇 第21章 再论IRP 第22章 过滤驱动程序 第23章 高级调试技巧

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值