我在自己的博客园http://www.cnblogs.com/DotCpp/archive/2010/01/27/DotCpp.html和百度空间http://hi.baidu.com/anglecloudy/blog/item/9b8d841636c6b84321a4e901.html中已经讲的差不多了。只是内容有点乱,现在在这里面好好整理一下。为初学者提供学习方法及自己做个备份。【注:转载请注明出处,打这么多字不容易,呵呵:)】
一、开篇--工具下载与安装
1>> 我使用的是工具VC + XPDDK +DriverStudio 3.1(DriverStudio是为了用里面的几个测试工具,如DriverMonitor,而且还可以学一下WDM开发) 。很多人现在用的是DriverStudio 3.2,我开始也用的是3.2,只是有段时间学习武安河的那本《Windows 2000 XP WDM 开发》时他用的是3.1,与3.2界面差别有点大,而且当时对驱动不太了解,为了学习方便只能换3.1,找了很久的下载地址:http://blog.youkuaiyun.com/mobidogs/archive/2007/01/23/1491503.aspx
现在想想有些不值,武安河的那本书没能坚持下来。那本书一点都不适合初学者看。后来看的《Windows驱动开发技术详解》收获很大,学到了很多东西。建议初学者先那本书,再看其它书籍。
相关软件可以从网站http://www.moodisk.com/download_other_c.php下载,如:
(1)·DriverStudio_3.2_CR.rar(解压DriverStudio_3.2_CR.rar,进入解压后的目录DriverStudio_3.2_CR,再把其中 driverstudio.3.2.crack.rar解压,产生目录driverstudio.3.2.crack,里面有两个文件SN.txt和 compuware.dat,前者包含序列号,后者是证书文件,这两个文件在安装过程中会用到。)
(2)·Visual.C++.6.EN.zip;
(3)·winxp_ddk.rar;
(4)·ntstrsafe.lib+csq.lib.rar;
2>>安装,没啥好说的。安装顺序:--> VC6.0-->VC SP6补丁 --> WinXP_DDK (安装DDK时把Build Envirement里面的win 2000选中(默认的是没选中,要注意),不然以后编译DDK例子时,ntddk.h里面会出现很多错误,而且基本都是有些类型找不到定义,这时你把2000 DDK的头文件加在Directory的Include里面就行了,曾经我被搞的痛不欲生)-> DriverStudio3.x(1,2都行)
3>>配置:在Tool-> Options设置Include和Lib目录,注意是2000 DDK的(如果等下编译有什么问题,把XP DDK的一些头文件和LIB文件也加进来,基本就没问题了)。
我的设置是Include目录:
C:\WINDDK\2600\INC\W2K
C:\WINDDK\2600\INC\DDK\W2K
C:\WINDDK\2600\INC\DDK\WDM\W2K
Lib目录:
C:\WINDDK\2600\LIB\W2K\I386
二、测试代码
1>>自己写的HelloDDK,其实和《Windows驱动开发技术详解》差不多。呵呵,大鸟不要见怪,我说的重点是第二点。
#ifdef __cplusplus
extern "C"
{
#endif
#include <NTDDK.h>
#ifdef __cplusplus
}
#endif
#define PAGEDCODE code_seg("PAGE")
#define LOCKEDCODE code_seg()
#define INITCODE code_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;
/************************************************************************
* 函数名称:CreateDevice
* 功能描述:初始化设备对象
* 参数列表:
pDriverObject:从I/O管理器中传进来的驱动对象
* 返回 值:返回初始化状态
*************************************************************************/
#pragma INITCODE
NTSTATUS CreateDevice (
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;
}
/************************************************************************
* 函数名称:HelloDDKUnload
* 功能描述:负责驱动程序的卸载操作
* 参数列表:
pDriverObject:驱动对象
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject)
{
PDEVICE_OBJECT pNextObj;
KdPrint(("Enter DriverUnload\n"));
pNextObj = pDriverObject->DeviceObject;
while (pNextObj != NULL)
{
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pNextObj->DeviceExtension;
//删除符号链接
UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
IoDeleteSymbolicLink(&pLinkName);
pNextObj = pNextObj->NextDevice;
IoDeleteDevice( pDevExt->pDevice );
}
}
/************************************************************************
* 函数名称:HelloDDKDispatchRoutine
* 功能描述:对读IRP进行处理
* 参数列表:
pDevObj:功能设备对象
pIrp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp)
{
KdPrint(("Enter HelloDDKDispatchRoutine\n"));
NTSTATUS status = STATUS_SUCCESS;
// 完成IRP
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0; IoCompleteRequest( pIrp, IO_NO_INCREMENT );
KdPrint(("Leave HelloDDKDispatchRoutine\n"));
return status;
}
/************************************************************************
* 函数名称: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 = 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 = CreateDevice(pDriverObject);
KdPrint(("DriverEntry end\n"));
return status;
}
2>>设置编译环境
*开始C/C++选项卡里的设置。
1)Preprocessor definitions中设置为:WIN32=100,_X86_=1,WINVER=0x500,DBG=1
WIN32=100:不是很清楚。
_X86_=1:这个最重要,否则无法编译通过。代表CPU类型为X86
WINVER=0x500,是因为你是for 2K的。XP的是0x501。
DGB=1表示调试版本。
2)C++ Language里面去掉Enable exeception handling,否则会出现error LNK2001: unresolved external symbol ___CxxFrameHandler。
3)Code Generation调用习俗设置成__stdcall。
4)Project Options中去掉/GZ【注意是大写的GZ】,目的是编译的时候不会自动加入__chkesp。
5)Precompiled Headers里面选Not using Precompiled headers,毕竟驱动程序都不会太大,不在乎节省那点时间。
*设置Link选项卡
1)输出改成*.sys
2)lib添加ntoskrnl.lib
3)勾上Ignore all default libraries,否则会链接libc,报告没有main函数。
4)Base address:0x10000
Entry-point sysmbol:DriverEntry
Statck Reverse:0x400000,缺省是1MB,但为什么要设成4MB?
Commit:0x1000
5)Customize去掉Link incrementally,否则会和/RELEASE冲突。
6)link的 Project Options:加入/subsystem:native /driver /SECTION:INIT,D /RELEASE /IGNORE:4078
/subsystem:native:PE格式文件其中有个地方要填写这个。
/driver是对驱动做一些优化。
/SECTION:INIT,D:对INIT section进行discard
/RELEASE (Set the Checksum)
/IGNORE:4078 忽略4078错误,否则会出现LINK : warning LNK4078: multiple "INIT" sections found with different attributes (E2000020)
3>> 配置好后,生成相关的sys文件即可,用DriverMonitor加载一下就可以看到效果了。祝大家成功
附:本文没有讲WDM,如果学习WDM,可以去我的百度空间和博客园看一下。不过建议初学者先别学那个,怎么一个痛苦了得
written by .cpp