郁闷,做了WCE嵌入式驱动这么久还没热身够,又被调到做window xp下的驱动开发。没办法。只能受令了。
现在就开始自己的学习之旅吧。
转载请标明是引用于 http://blog.csdn.net/chenyujing1234
欢迎大家提出意见,一起讨论!
示例源码:(VS2008)
window的驱动开发有两种方法 DDK与WDK,我选择WDK,因为 windows xp 驱动开发(三)DDK与WDK 的区别
=================================================================
转自: http://www.cnblogs.com/wangjunchao/archive/2010/09/15/DDKSetup.html
开发驱动,首先就是搭建开发的环境。既然是开发windows下的驱动程序,那MS的开发工具是一定要的。现在vs都到2010了,所以,也不能总是抱着vs6.0写代码,也要与时俱进~当然又不能太潮流吗……所以选用vs2008开发驱动。好了废话不多说了,下面记录一下我搭环境的步骤。只是个人的经历和测试,免不了会有些错,希望大家能指出。
一、VS2008的安装
这个……大家肯定比我熟的多,所以就不再显眼了。
vs2008的下载及正版升级见:http://bbs.51aspx.com/showtopic-1714.html
vs2008的详细安装见:Visual Studio 2008系列教程(一):VS 2008安装详解!
ok 接下来该驱动开发的核心了……
二、WDK的介绍、下载、安装及配制
1、关于WDK
Windows Driver Kit(驱动程序工具包): 是一种完全集成的驱动程序开发系统,它包含 Windows Driver Device Kit (DDK),用于测试 Windows 驱动程序的可靠性和稳定性,包括:
2、下载WDK
曾经下载WDK好像还必须得http://connect.microsoft.com/注册后才能下载,而且下载后还有一句提示:
“提醒:您必须接受附带的许可条款才能使用此软件。不得分发下载软件包。”
所以当时下载的时候还要走一些不得不走的路。不过,今天好像发现WDK能直接下载了
下载地址:http://download.microsoft.com/download/4/A/2/4A25C7D5-EFBE-4182-B6A9-AE6850409A78/GRMWDK_EN_7600_1.ISO
如果不能正常下载,具体操作请见如何下载WDK
3、安装WDK
1、用虚拟光驱加载下载好的.ISO镜像文件,双击运行,出现下面亲切的画面
注意:因为我们的安装文件是GRMWDK_EN_7600_1.ISO,而如果我们的电脑上安装了 UltraISO软件,那么默认是用它打开的,这时我们双击KitSetup.exe,时会提示出错信息:KitSetup Base Initailization Error!(Code: 0x00022) Missing Software Kit Object Model(SKOM)definition for kit......
原因:这是因为我们没有把.iso文件全部解压,安装时提示安装文件缺失。
解决方法:右击GRMWDK_EN_7600_1.ISO,选择UtraISO->安装到驱动器H盘。然后到我的电脑的驱动器H盘安装。
2、接触,出现以下画面,在左侧的树形复选框中选择要安装的组件及工具,建议全部安装,选择好后点击“OK”~~后面的就简单了~
3、尔后,一路确定默认即可
三、DDKWzard的介绍、下载、安装及配制
在VS2008IDE中没有提供驱动开发的项目选项,当然可以用普通工程,然后手动在VS中配制相应的编辑连接以及调试选项,但是如此一来,每次都要重复些复杂的步骤。在http://ddkwizard.assarbad.net/网站上发现了一个很好用的辅助工具DDKWizard,能够方便地对开发环境进行配置,真是适合想我这样懒人啊,工具的作者也自称是因为懒惰才开发此工具,看来“懒惰是推动科技发展的动力”一点不假 。
如果为其它系统开发驱动则填写相应的环境变量
NT 4.0 ———–NT4BASE
windows2000—-W2KBASE
windowsXP——-WXPBASE
windows2003—-WNETBASE
win7/2008 R2—-W7BASE
四:可能出现的错误
Error: "fatal error U1087: cannot have : and :: dependents for same target"
解决方案: 解保你的编译路径中没空格.
五:友情提示
在用VS2008开发驱动时,建议在菜单“视图”->“输出”(或快捷键:Ctrl+W,O)开启项目的输出显示,能显示项目生成时的细节!
Driver3.h
#include "drvcommon.h"
#include "drvversion.h"
在drvcommon.h里有一个重要的宏
#define PRESET_UNICODE_STRING(symbol, buffer) \ UNICODE_STRING symbol = \ { \ sizeof(WIDESTRING(buffer)) - sizeof(WCHAR), \ sizeof(WIDESTRING(buffer)), \ WIDESTRING(buffer) \ };
通过它drvcommon.h里定义变量usDeviceName、usSymlinkName,这两个变量在Drivers.cpp里的DriverEntry、DRIVER3_DriverUnload函数中被调用。
#define DEVICE_NAME "\\Device\\DRIVER3_DeviceName" #define SYMLINK_NAME "\\DosDevices\\DRIVER3_DeviceName" PRESET_UNICODE_STRING(usDeviceName, DEVICE_NAME); PRESET_UNICODE_STRING(usSymlinkName, SYMLINK_NAME);
#include <ntddk.h> // 在D:\WINDDK\3790.1830\inc\ddk\wxp
#include <string.h>
#include "Driver3.h"
在第一点中讲到了DriverEntry、DRIVER3_DriverUnload两函数。下面重点介绍.
一个特定的驱动程序可能会被一个以上的相似硬件所使用,并且存在一些只需要在其第一次加载时被执行一次的全局初始化操作。DriverEntry程序负责这些全局初始化操。
注: 如果你用的是标准的编译程序,你能以“DriverEntry”程序为主入口点来调用内核模式驱动程序,这是因为在构建脚本(Build Script)中已经定义,其会命令连接器将其连接为默认的主入口点,你最好也令你的代码和这相符(否则修改构建脚本,但这有必要么?) |
关于需要你注意的该函数原型的最后一点是其声明了一NTSTATUS值作为返回值。NTSTATUS实际上只是一个长整型。但为了你代码更好的可读性你应该用类型定义名NTSTATUS来代替LONG。很多内核模式支持程序都能返回NTSTATUS状态码,状态码的定义你可以在DDK的头文件NTSTATUS.H中找到。关于状态码在下一章我将会介绍更多。目前,你只需知道当你的DriverEntry函数执行完毕时其会返回状态码。
WDM驱动程序的DriverEntry的主要工作是给驱动对象填入各种的函数指针。这些指针为操作系统指明了驱动程序容器中各种子程序的位置。驱动对象中的指针包括如下内容:
DriverUnload
用来来指向你创建的清除程序。I/O管理器只会在卸载驱动之前调用该程序。如果没有任何需要清除的,你需要给系统一个DriverUnload函数来动态地卸载你的驱动。
DriverExtension->AddDevice
用来指向AddDevice函数。即插即用管理器会为每一个你负责的硬件实例调用一次AddDevice。由于AddDevice对于WDM驱动的工作方式非常要
DriverStartIo
如果驱动程序使用标准的队列I/O请求方式,你应该设置这组驱动对象指向StartIo程序。不要担心(但确实是这样)是否明白我所说的“标准的”队列方式。其实你会发现WDM驱动不应该使用它。
MajorFunction
I/O管理器初始化该函数指针向量来指向哑元派遣函数,该哑元派遣函数返回每个请求的失败。你大概只需要处理几种IRP的类型——否则驱动程序基本上就废了,所以至少应该设置与那几种IRP类型相对应的指针元素,使它们指向相应的派遣函数。
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { NTSTATUS ntStatus = STATUS_SUCCESS; // 设定了在驱动中别处的函数指针的入口点 DriverObject->DriverExtension->AddDevice = TestAddDevice; DriverObject->DriverUnload = TestDrvUnload; // 设置请求派遣函数 DriverObject->MajorFunction[IRP_MJ_PNP] = TestPnpIrp; DriverObject->MajorFunction[IRP_MJ_POWER] = TestPowerIrp; DriverObject->MajorFunction[IRP_MJ_CREATE] = TestCreate; DriverObject->MajorFunction[IRP_MJ_CLOSE] = TestClose; DriverObject->MajorFunction[IRP_MJ_READ] = TestRead; DriverObject->MajorFunction[IRP_MJ_WRITE] = TestWrite; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TestIOCTL; // 复制RegistryPath字符串,使在驱动的别的地方可以访问注册表服务键值 servkey.Buffer = (PWSTR) ExAllocatePool(PagedPool, RegistryPath->Length + sizeof(WCHAR)); if (!servkey.Buffer) return STATUS_INSUFFICIENT_RESOURCES; servkey.MaximumLength = RegistryPath->Length + sizeof(WCHAR); RtlCopyUnicodeString(&servkey, RegistryPath); servkey.Buffer[RegistryPath->Length/sizeof(WCHAR)] = 0; return ntStatus; }
WDM驱动的DriverUnload函数的目的是清理DriverEntry所做的所有全局初始化操作。其几乎无事可做。若你在DriverEntry中复制了RegistryPath字符串,DriverUnload则会在此释放内存。代码如下:
void TestDrvUnload(IN PDRIVER_OBJECT DriverObject) { RtlFreeUnicodeString(&servkey); }