写驱动的加载需要用到五个函数:

OpenSCManager()

CreateService()

OpenService()

StartService()

CloseServiceHandle()

这五个函数的作用和用法,我在代码中会进行说明。

正常加载驱动的步骤如下:

1、调用 OpenSCManager 这个 Win32 API 函数来打开 SCM 服务管理器,如果返回值为:NULL,则表示打开失败,否则表示打开成功并继续下一步执行。

2、调用 CreateService 这个 Win32 API 函数来创建服务,然后用 GetLastError 函数获取返回值,如果返回值为:ERROR_IO_PENDING,则说明服务已经创建过。

3、然后,此时用 OpenService 这个 Win32 API 函数打开此服务。

4、调用 StartService 这个 Win32 API 函数来开启此服务。

5、最后调用 CloseServiceHandle() 对错误信息进行一个简单的处理。

当我点击加载驱动按钮后,弹出打开文件对话框,然后选择驱动文件,进行加载这个过程我写在 Load Driver 按钮的单击事件中。

下面看代码:

static CStringW DriverName;  //保存驱动名称的全局变量
CEdit * pEditA;
CString CirLf,AddEditSrt;

BOOL LoadNTDriver(WCHAR* pDriverName, WCHAR* pDriverPathName);
void CLoadDriverToolsDlg::On_btnLoadD_Clicked()
{
CEdit * pEdit =(CEdit*)GetDlgItem(IDC_txtGetSysName); //获取 EDIT 控件的句柄,并转换成 CEdit 控件类指针
pEditA = pEdit;
CirLf = ".\r\n"; // \r\n表示换行 WCHAR *Filters = L"All File(*.*)|*.*|Driver File(*.sys)|*.sys|";
WCHAR *DefaultFileter = L"All File(*.*)|*.*|";
WCHAR *DefaultFileName = L"请选择驱动文件"; /*CFileDialog 类封装了Windows常用的文件对话框。常用的文件对话框提供了文件打开和文件存盘对话框功能。
DoModal 代表这个窗口变成当前窗口,而且此函数一直阻塞知道你点OK或者Cancel退出,如果点的时候OK,该函数返回值为IDOK。
IDOK 按钮默认响应CDialog::OnOK();这个虚函数。这个函数调用EndDialog(IDOK);EndDialog设置对话框返回值,IDOK就是返回值。*/
CFileDialog FileDlg(true, DefaultFileter, DefaultFileName, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, Filters, NULL);
if (FileDlg.DoModal() == IDOK){
DriverName = FileDlg.GetFileName();
pEditA->SetWindowTextW(AddEditSrt += L"打开的驱动名称为:" + DriverName + CirLf); } /*能GetBuffer函数,说明这个函数是为一个CString对象,可重新获取其内部字符缓冲区的指针,
返回的LPTSTR为非const的,从而允许直接修改CString中的内容,里面的参数表示缓冲区的大小*/
WCHAR *DriverNameBuffer = DriverName.GetBuffer(DriverName.GetLength());
BOOL Status =LoadNTDriver(DriverNameBuffer, FileDlg.GetPathName().GetBuffer());
if (Status == false){
printf("服务启动失败!!错误代码为:%d \n", GetLastError());
MessageBox(L"服务启动失败!!", L"消息框", MB_OK);
}
else{
printf("服务启动成功! \n");
MessageBox(L"服务启动成功!", L"消息框", MB_OK);
Status = true;
} }
 

这里有个自定义的驱动加载函数,并传递了两个参数,一个驱动名称,一个驱动路径。而整个加载的过程,可以写在头文件里面,我这里就直接写在源文件中,

下面看代码:

BOOL LoadNTDriver(WCHAR* pDriverName, WCHAR* pDriverPathName){
BOOL Status = false;
SC_HANDLE hServiceManager = NULL;
SC_HANDLE hServiceDriver = NULL; //打开服务管理器
hServiceManager = OpenSCManager(
NULL, //指定目标计算机的名称。如果该指针为NULL ,就连接到本地主机的服务控制器。
SERVICES_ACTIVE_DATABASE, //指定将要打开的服务控制管理数据库的名称。
SC_MANAGER_CREATE_SERVICE //如果该指针为NULL ,则打开默认的 SERVICES_ACTIVE_DATABASE
); //返回值为服务管理器的句柄
if (hServiceManager != NULL){ /*TRACE 宏有点象C语言中用的Printf函数,使程序在运行中输出一些调试信息。
但有一点不同的是:TRACE 宏只有在调试状态下才有所输出,而以前用的Printf 函数在任何情况下都有输出。*/
printf("打开服务管理器成功! \n");
pEditA->SetWindowTextW(AddEditSrt += L"打开服务管理器成功!" + CirLf); //创建服务
hServiceDriver = CreateService(
hServiceManager, //服务管理器的句柄,由系统函数OpenSCManager 返回
pDriverName, //驱动程序在注册表中的名称,最大字符串长度为 256 个字符
pDriverName, //被用户界面程序用来识别服务的显示名称。此字符串具有最大长度为 256 个字符。
SERVICE_ALL_ACCESS, //加载驱动程序时所具备的访问权限
SERVICE_KERNEL_DRIVER, //服务类型,此枚举表示加载的服务是驱动程序
SERVICE_DEMAND_START, //服务启动选项,此枚举表示由服务控制管理器(SCM)启动的服务,也就是需手动启动。
SERVICE_ERROR_IGNORE, //当该启动服务失败时产生错误及采取的保护措施, 此枚举表示服务启动程序将忽略该错误并返回继续执行。
pDriverPathName, //注册表中驱动程序所在的路径
NULL,
NULL,
NULL,
NULL,
NULL
); //返回值为服务的句柄
if (hServiceDriver != NULL){
printf("创建服务成功! \n");
pEditA->SetWindowTextW(AddEditSrt += L"创建服务成功!" + CirLf); //打开创建的服务
hServiceDriver = OpenService(
hServiceManager, //服务管理器的句柄
pDriverName, //服务的名称
SERVICE_ALL_ACCESS //打开服务所需的访问权限,此枚举为完全权限
); //返回值为服务的句柄
if (hServiceDriver != NULL){
printf("打开服务成功! \n");
pEditA->SetWindowTextW(AddEditSrt += L"打开服务成功!" + CirLf); //启动创建的服务
INT reValue = StartService(
hServiceDriver, //要打开的服务的服务句柄
NULL, //服务向量数组中的字符串数量,如果字符串数量为空,该参数可以是零。
NULL //字符串被传递给服务的ServiceMain函数作为参数。如果没有参数,可以为空。
); //如果启动成功返回非零的数,否则返回零
if (reValue != ){
TRACE("启动服务成功! \n");
pEditA->SetWindowTextW(AddEditSrt += L"启动服务成功!" + CirLf);
Status = true;
return Status;
}
else{
printf("StartService() Fild %d ! \n", GetLastError());
pEditA->SetWindowTextW(AddEditSrt += L"启动服务失败!!错误代码为:" + GetLastError() + CirLf);
goto a; //出现错误后,调到a处,进行处理
}
}
else{
printf("OpenService() Fild %d ! \n", GetLastError());
pEditA->SetWindowTextW(AddEditSrt += L"打开服务失败!!错误代码为:" + GetLastError() + CirLf);
goto a;
}
}
else{
printf("CreateService() Fild %d ! \n", GetLastError());
pEditA->SetWindowTextW(AddEditSrt += L"创建服务失败!!错误代码为:" + GetLastError() + CirLf);
goto a;
}
}
else{
printf("OpenSCManager() Fild %d ! \n", GetLastError());
pEditA->SetWindowTextW(AddEditSrt += L"打开服务管理器失败!!错误代码为:" + GetLastError() + CirLf);
goto a;
} //用 CloseServiceHandle 函数来关闭服务管理器或服务
a: if (hServiceManager){ //如果打开了服务管理器,就关闭服务管理器
CloseServiceHandle(hServiceManager);
}
if (hServiceDriver){ //如果打开了服务,就关闭服务
CloseServiceHandle(hServiceDriver);
}
return Status;
}

好了,加载驱动的过程以编写完毕,下面看下效果:

驱动加载并成功启动!!

下面我们写一个卸载驱动的过来,让这个工具能加载也能卸载!

卸载驱动的过程需要用到四个函数:

OpenSCManager()     //打开服务管理器

OpenService()             //打开要卸载的服务

ControlService()        //发送控制命令来停止要卸载的服务

DeleteService()        //删除要卸载的服务

同样,当我点击卸载驱动按钮后,就进行卸载,这个过程我写在 Unload Driver 按钮的单击事件中。

下面看代码:

BOOL UnloadNTDriver(WCHAR* lpDriverName);
void CLoadDriverToolsDlg::On_btnUnloadD_Clicked()
{ BOOL Status = UnloadNTDriver(DriverName.GetBuffer(DriverName.GetLength()));
if (Status = true){
printf("服务卸载成功!\n");
MessageBox(L"服务卸载成功!", L"消息框", MB_OK);
}
else{
printf("服务卸载失败!!错误代码为:%d \n",GetLastError());
MessageBox(L"服务卸载失败!!", L"消息框", MB_OK);
}
}

这里有个自定义的驱动卸载函数,并传递了一个参数,一个驱动名称的缓冲区指针。而整个卸载过程,可以写在头文件里面,我这里就直接写在源文件中,

下面看代码:

BOOL UnloadNTDriver(WCHAR* lpDriverName){
BOOL Status = false;
SC_HANDLE hServiceManager = NULL;
SC_HANDLE hServiceDriver = NULL;
SERVICE_STATUS SaveValue; // SERVICE_STATUS 显示了服务器上运行的服务状态信息。 //打开服务管理器
hServiceManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE);
if (hServiceManager != NULL){
printf("服务管理器打开成功!\n");
pEditA->SetWindowTextW(AddEditSrt += L"服务管理器打开成功!" + CirLf); //打开服务
hServiceDriver = OpenService(hServiceManager, lpDriverName, SERVICE_ALL_ACCESS);
if (hServiceDriver != NULL){
printf("服务打开成功!\n");
pEditA->SetWindowTextW(AddEditSrt += L"服务打开成功!" + CirLf);
int StatusValue; //想要顺利卸载驱动,必先停止驱动,所以用ControlService函数发送控制命令.
StatusValue = ControlService(hServiceDriver, SERVICE_CONTROL_STOP, &SaveValue);
if (StatusValue > ){
printf("服务停止成功!\n");
pEditA->SetWindowTextW(AddEditSrt += L"服务停止成功!" + CirLf);
/*我们把 ControlService 函数读出的 SERVICE_STATUS 服务状态信息打印出来看看,
上面,我们以保存在 SaveValue 这个变量中了,所以现在只需读取这个变量就行。*/
printf("停止服务的过程已经执行了,那现在的状态是:=%d \n", &SaveValue); //卸载驱动,此函数从服务控制管理器数据库删除指定的服务
StatusValue = DeleteService(hServiceDriver);
if (StatusValue > ){
printf("服务卸载成功!\n");
pEditA->SetWindowTextW(AddEditSrt += L"服务卸载成功!" + CirLf);
Status = true;
return Status;
}
else{
printf("服务卸载失败!!错误代码为:=%d \n", GetLastError());
pEditA->SetWindowTextW(AddEditSrt += L"服务卸载失败!!错误代码为:" + GetLastError() + CirLf);
goto b;
}
}
else{
printf("服务停止失败!!错误代码为:=%d \n", GetLastError());
pEditA->SetWindowTextW(AddEditSrt += L"服务停止失败!!错误代码为:" + GetLastError() + CirLf);
goto b;
}
}
else{
printf("服务打开失败!!错误代码为:=%d \n", GetLastError());
pEditA->SetWindowTextW(AddEditSrt += L"服务打开失败!!错误代码为:" + GetLastError() + CirLf);
goto b;
}
}
else{
printf("服务管理器打开失败!!错误代码为:=%d \n", GetLastError());
pEditA->SetWindowTextW(AddEditSrt += L"服务管理器打开失败!!错误代码为:" + GetLastError() + CirLf);
goto b;
} //如果出现错误,就对句柄进行处理
b: if (hServiceManager){
CloseServiceHandle(hServiceManager);
}
if (hServiceDriver){
CloseServiceHandle(hServiceDriver);
}
return Status;
}

大功告成!!验证结果见下图:

编写简单的 NT 式驱动程序的加载与卸载工具的更多相关文章

  1. C++第三十八篇 -- 研究一下Windows驱动开发(二)--WDM式驱动的加载

    基于Windows驱动开发技术详解这本书 一.简单的INF文件剖析 INF文件是一个文本文件,由若干个节(Section)组成.每个节的名称用一个方括号指示,紧接着方括号后面的就是节内容.每一行就是一 ...

  2. Qt中如何 编写插件 加载插件 卸载插件

    Qt中如何 编写插件 加载插件 卸载插件是本文要介绍的内容.Qt提供了一个类QPluginLoader来加载静态库和动态库,在Qt中,Qt把动态库和静态库都看成是一个插件,使用QPluginLoade ...

  3. Lodop的JS模版代码、文档式模版 生成加载赋值博文索引

    Lodop获取全部JS代码,传统JS模版的生成.LODOP设置打印设计返回JS代码是变量 LodopJS代码模版的加载和赋值 Lodop生成文档式模版 LodopJS文档式模版的加载和赋值 由于加载J ...

  4. LodopJS文档式模版的加载和赋值

    Lodop模版有两种方法,一种是传统的JS语句,可以用JS方法里的eval来执行,一种是文档式模版,是特殊格式的base64码,此篇博文介绍文档式模版的加载,文档式模版的生成以及传统JS模版的生成加载 ...

  5. 事件ID:7026(“下列引导或系统启动驱动程序无法加载: cdrom”)的解决方法

     电脑没有安装光驱,而是使用USB光驱/虚拟光驱软件,每次开机后"事件查看器"都显示错误:"下列引导或系统启动驱动程序无法加载: cdrom"(事件ID:7 ...

  6. java反射并不是什么高深技术,面向对象语言都有这个功能,而且功能也很简单,就是利用jvm动态加载时生成的class对象

    java反射并不是什么高深技术,面向对象语言都有这个功能. 面向对象语言都有这个功能,而且功能也很简单,就是利用jvm动态加载时生成的class对象,去获取类相关的信息 2.利用java反射可以调用类 ...

  7. AutoCAD配置的Heidi驱动程序未加载

    电脑安装的软件越来越多,有的软件也就偶尔使用一下下,于是就找了一个绿化版的AutoCAD,挺好的,可启动时弹出"配置的Heidi驱动程序未加载.切换到默认软件驱动程序". 对于上述 ...

  8. C#.Net 如何动态加载与卸载程序集(.dll或者.exe)0-------通过应用程序域AppDomain加载和卸载程序集

    本博客中以“C#.Net 如何动态加载与卸载程序集(.dll或者.exe)”开头的都是引用莫问奴归处 微软装配车的大门似乎只为货物装载敞开大门,却将卸载工人拒之门外.车门的钥匙只有一把,若要获得还需要 ...

  9. 通过应用程序域AppDomain加载和卸载程序集

    微软装配车的大门似乎只为货物装载敞开大门,却将卸载工人拒之门外.车门的钥匙只有一把,若要获得还需要你费一些心思.我在学习Remoting的时候,就遇到一个扰人的问题,就是Remoting为远程对象仅提 ...

随机推荐

  1. Tornado模块分类和各模块之间的关系

    1. Core web framework tornado.web — 包含web框架的大部分主要功能,包含RequestHandler和Application两个重要的类 tornado.https ...

  2. 为什么memset不能将数组元素初始化为1?

    原型:extern void *memset(void *buffer, int c, int count); 功能:把buffer所指内存区域的前count个字节设置成字符c. 包含头文件:< ...

  3. linux管理员切换与管理员密码第一次设置

    在终端输入su - root回车来切回到超级管理员,Ubuntu的默认超级管理员root密码是随机的,即每次开机都有一个新的root密码.我们可以在终端输入命令 sudo passwd,然后输入当前用 ...

  4. Redis使用(1)---安装

    简介 Redis具体简介可以百度.它可以在Linux和Windows下运行,但官方只提供针对Linux的包,Windows对其也有自己的开发团队. redis官网:http://www.redis.i ...

  5. OC与Swift混编

    群里大神发的网址,感觉有用就先收录了,暂时没时间看SWIFT,感觉代码简洁,但是可阅读性不是太高,有些代码让系统去判断类型,同样的,我们看代码的时候也得自己去判断类型,或许看多就习惯了,有时间再说吧, ...

  6. filter 以及 orderBy的使用

    filter用于关键字过滤操作,orderBy用于排序操作,运行界面如下: 点击标题Name与Email实现排序功能,输入框中输入关键字进行过滤,同时实现根据关键字进行过滤后进行排序操作: ng-re ...

  7. poj2960 S-Nim

    大意:有n堆石子,每堆石子个数已知,两人轮流从中取石子, 每次可取的石子数x满足x属于集合S(k) = {s1,s2,s3...sk-1},问先拿者是否有必胜策略? 裸nim,可以用记忆化搜索. #i ...

  8. HDU 3401 Trade(单调队列优化)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3401 题意:炒股.第i天买入一股的价钱api,卖出一股的价钱bpi,最多买入asi股,最多卖出bsi股 ...

  9. C51 函数/程序段的定位

    在Keil C中可能需要指定某个函数或者某段程序链接后存放在程序区中的位置. 1. 如何指定某个函数在程序区中的位置. QUESTION How do I locate a C function at ...

  10. cocos2d-x特效之CCControlPotentiometer

    在test示例下面,有一个关于此功能的代码,实现的效果如下: 通过拉动可旋转的按钮,从而改变所代表的值,这个效果的确是很棒的,但,和我的需求有一些差别,先贴上我实现的效果吧               ...