注:在本文最后附加源代码工程
在windows平台下驱动分为WDM式和NT式2种类型,NT式驱动不支持即插即用,而WDM式可以支持,小悠现在目前学的是NT式的驱动基础,对驱动的知识也算是比较了解了吧,今天在程序中第一次调用了自己的驱动,这里就给大家分享一下NT式驱动的加载方式吧.
下面我将从驱动运行的方式和驱动加载的步骤来讲解NT式驱动的加载方法.
· 循环渐进,从基础说起
设备驱动程序的动态加载主要是有服务控制管理程序(Service Control Manager,简称 SCM)系统组件来完成的。SCM为Windows中运行的组件提供了很多服务,比如像启动啊,停止啊,控制啊等等,所以要想用代码动态加载你的驱动的话就得和这货打交道。
Windows中的服务可以在系统启动的时候加载,或者你自己在服务管理中自己手动开启或者关闭之类的。在代码中我们可以通过windows提供的相关服务函数进行驱动的加载、卸载操作;
加载NT式驱动一般分为下面的几个步骤:
① 打开SCM这货
② 创建你自己的驱动对应的服务
③ 开启你的这个服务,让它跑起来
卸载NT式驱动一般分为下面的几个步骤:
① 依然先打开SCM这货
② 打开你的驱动服务
③ 停止你的驱动
④ 干掉驱动,就卸载成功了
· 说说加载驱动的时候用的一些操作函数
1、 打开SCM管理器函数
SC_HANDLE OpenSCManager(
LPCTSTR lpMachineName, //计算机的名字
LPCTSTR lpDatabaseName,//SCM数据库名称
DWORD dwDesireAccess//权限
)
lpMachineName:指定一个计算机的名称,使用NULL表示本机操作。
lpDatabaseName:指定SCM数据的名称,使用NULL表示使用默认的数据库
dwDesireAccess:表示你的访问权限,一般设置为SC_MANAGER_ALL_ACCESS
这个函数如果调用成功就返回SCM管理器的句柄,失败的话返回一个NULL
2、 关闭服务句柄
对于服务来说,使用的是SC_HANDLE这个类型保存的句柄,所以要是用函数CloseServiceHandle()这个函数去关闭句柄.
3、 创建一个你自己的服务
下面的这个函数是创建一个你的服务,他将返回一个与你的服务相关的句柄,以后对你的服务操作全部都是基于这个句柄的。下面是这个函数的原型,它位于WinSvc.h中:
SC_HANDLE
CreateService(
SC_HANDLE hSCManager,
LPCWSTR lpServiceName,
LPCWSTR lpDisplayName,
DWORD dwDesiredAccess,
DWORD dwServiceType,
DWORD dwStartType,
DWORD dwErrorControl,
LPCWSTR lpBinaryPathName,
LPCWSTR lpLoadOrderGroup,
LPDWORD lpdwTagId,
LPCWSTR lpDependencies,
LPCWSTR lpServiceStartName,
LPCWSTR lpPassword
);
hSCManager:这是你的SCM管理器的句柄。
lpServiceName:服务的名字,就是一个字串,用它可以打开你的服务
lpDisplayName:服务显示的名称
dwDesiredAccess:打开的权限,一般设置为SERVICE_ALL_ACCESS
dwServiceType:服务的类型,其中SERVICE_FILE_SYSTEM_DRIVER表示文件系统类型的驱动,SERVICE_KERNEL_DRIVER表示普通的程序驱动,一般都是使用这货
dwStartType:服务打开的时间,是自动还是其他,SERVICE_AUTO_START表示自动加载,SERVICE_BOOT_START表示在系统启动前就被启动,SERVICE_DEMAND_START表示按照你的需要进行加载(手动),一般使用这个方式
dwErrorControl:设置有关错误的处理方式,SERVICE_ERROR_IGNORE表示忽略所有的错误,SERVICE_ERROR_NORMAL表示默认处理,SERVICE_ERROR_CRITICAL表示增加对错误处理的校验,弹出对话框,然后记录错误日志信息
lpBinaryPathName:你的sys文件的路径
lpLoadOrderGroup:指定你的用户组
lpdwTagId:输出验证标签
lpDependencies:所依赖的服务的名称
lpServiceStartName:用户的账户名称
lpPassword:用户的密码
4、 打开你所创建的服务
这个函数的话是针对你已经创建过的服务,再次打开的时候进行调用
SC_HANDLE
OpenService(
SC_HANDLE hSCManager,//SCM的句柄
LPCWSTR lpServiceName,//你的服务名称
DWORD dwDesiredAccess//访问的权限
);
5、 控制你的服务
这个函数就是对你的服务发送命令用于控制作用的
BOOL
ControlService(
SC_HANDLE hService,//服务的句柄
DWORD dwControl,//控制码
LPSERVICE_STATUS lpServiceStatus//返回的状态
);
· 驱动加载代码的执行流程
下面是NT驱动的加载流程,后面的代码就是根据这个流程来处理的.
① 首先使用OpenSCManager打开你的SCM管理器,如果返回了NULL,表示失败了,否则的话就继续
② 使用函数CreateService创建一个驱动的服务,如果成功的话跳转到⑥,返回NULL的话请继续
③ 因为返回了错误,但是错误不一定是致命的,比如我们的服务已经存在了,肯定会返回NULL的,所以这一步使用GetLastError获取到你的错误代码,继续
④ 因为③返回了错误,我们要对返回的错误码进行分析,如果返回值为ERROR_IO_PENDING或者ERROR_SERVICE_EXISTS这说明我们的服务已经存在了,直接使用OpenService进行打开操作
⑤ 如果OpenService返回NULL的话,就是失败了,退出
⑥ 使用函数StartService开启你的服务吧
⑦ 如果开启服务失败,再看看LastError的值,是被挂起了还是已经在运行了。
代码小悠将在最后附加:
· 驱动卸载代码的执行流程
① 还是先打开你的SCM管理器,失败就返回失败吧
② 打开你的驱动服务,注意一些错误的处理
③ 控制服务停止
④ 删除服务
小悠写了一个MFC下驱动加载的类,给大家分享一下,这里就简单的贴出类的头文件,说明一下函数的作用:
#include <winsvc.h> #ifndef MAX_PATH #define MAX_PATH 260 #endif #define MAX_NAME_SIZE MAX_PATH //加载驱动的错误类型 #define LOAD_SUCCESS 0x00//开启成功 #define LOAD_FAILED 0x01//开启失败 class CDriverLoad { public: CDriverLoad(void);//构造函数 virtual ~CDriverLoad(void); //驱动的加载函数,参数1:驱动的名字(自己起) //参数2:驱动的路径,可以使用相对路径,例如.\\A.sys DWORD LoadDriver(char* lpszRegName,char* lpszPath); //驱动的卸载函数 BOOL UnLoadDriver(); //获取到设备的句柄,这个我实现,直接使用CreateFile就行了 HANDLE GetDeviceHandle(); protected: //驱动文件的路径 CString m_szBinPath; //驱动的名字 CString m_szRegName; };
附上小悠写的一个MFC的例子(VS2010编写的)
解压密码 yscode
百度网盘下载地址:http://pan.baidu.com/s/1hqeMxda
本文出自悠然品鉴原创,请勿伪原创抄袭,转载请注明出处:http://www.youranshare.com/blog/sid/66.html