1. Windows驱动程序分为两类,一类是不支持即插即用功能的NT式的驱动程序;另一类是支持即插即用功能的WDM式的驱动程序。
2. NT式的驱动程序要导入的头文件时NTDDK.H,而WDM式的驱动要导入的头文件为WDM.H.
3. DriverEntry需要放在INIT标志的内存中。INIT标志指明该函数只是在加载的时候需要载入内存,而当驱动程序加载成功后,该函数可以从内存中卸载掉。

4.C++编写驱动需要注意:

[cpp] view plaincopy
  1. #ifdef  __cplusplus
  2. extern  “C”
  3. {
  4. #endif
  5. #include <NTDDK.H>
  6. #ifdef  __cplusplus
  7. }
  8. #endif
  9. #pragma  INITCODE  extern  “C”  NTSTATUS   DriverEntry(IN  PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING  pRegistryPath){}

5. 来看一个简单的NT式驱动

Driver.h:

[cpp] view plaincopy
  1. #pragma once
  2. #ifdef __cplusplus
  3. extern "C"
  4. {
  5. #endif
  6. #include <NTDDK.h>
  7. #ifdef __cplusplus
  8. }
  9. #endif
  10. #define PAGEDCODE code_seg("PAGE")
  11. #define LOCKEDCODE code_seg()
  12. #define INITCODE code_seg("INIT")
  13. #define PAGEDDATA data_seg("PAGE")
  14. #define LOCKEDDATA data_seg()
  15. #define INITDATA data_seg("INIT")
  16. #define arraysize(p) (sizeof(p)/sizeof((p)[0]))
  17. typedef struct _DEVICE_EXTENSION {
  18. PDEVICE_OBJECT pDevice;
  19. UNICODE_STRING ustrDeviceName;    //设备名称
  20. UNICODE_STRING ustrSymLinkName;    //符号链接名
  21. } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
  22. // 驱动函数声明
  23. NTSTATUS CreateDevice (IN PDRIVER_OBJECT pDriverObject);
  24. VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject);
  25. NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj,
  26. IN PIRP pIrp);

driver.cpp

[cpp] view plaincopy
  1. /************************************************************************
  2. * 函数名称:DriverEntry
  3. * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
  4. * 参数列表:
  5. pDriverObject:从I/O管理器中传进来的驱动对象
  6. pRegistryPath:驱动程序在注册表的中的路径
  7. * 返回 值:返回初始化驱动状态
  8. *************************************************************************/
  9. #pragma INITCODE
  10. extern "C" NTSTATUS DriverEntry (
  11. IN PDRIVER_OBJECT pDriverObject,
  12. IN PUNICODE_STRING pRegistryPath    )
  13. {
  14. NTSTATUS status;
  15. KdPrint(("Enter DriverEntry\n"));
  16. //注册其他驱动调用函数入口
  17. pDriverObject->DriverUnload = HelloDDKUnload;
  18. pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutine;
  19. pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutine;
  20. pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutine;
  21. pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutine;
  22. //创建驱动设备对象
  23. status = CreateDevice(pDriverObject);
  24. KdPrint(("DriverEntry end\n"));
  25. return status;
  26. }
  27. /************************************************************************
  28. * 函数名称:CreateDevice
  29. * 功能描述:初始化设备对象
  30. * 参数列表:
  31. pDriverObject:从I/O管理器中传进来的驱动对象
  32. * 返回 值:返回初始化状态
  33. *************************************************************************/
  34. #pragma INITCODE   //指明此函数加载到INIT内存区域(即只在加载的时候需要载入内存,加载成功后可以从内存中卸载掉)
  35. NTSTATUS CreateDevice (
  36. IN PDRIVER_OBJECT    pDriverObject)
  37. {
  38. NTSTATUS status;
  39. PDEVICE_OBJECT pDevObj;
  40. PDEVICE_EXTENSION pDevExt;
  41. //创建设备名称
  42. UNICODE_STRING devName;
  43. RtlInitUnicodeString(&devName,L"\\Device\\MyDDKDevice");
  44. //创建设备
  45. status = IoCreateDevice( pDriverObject,
  46. sizeof(DEVICE_EXTENSION),
  47. &(UNICODE_STRING)devName,
  48. FILE_DEVICE_UNKNOWN,//此种设备为独占设备
  49. 0, TRUE,
  50. &pDevObj );
  51. if (!NT_SUCCESS(status))
  52. return status;
  53. pDevObj->Flags |= DO_BUFFERED_IO;
  54. pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
  55. pDevExt->pDevice = pDevObj;
  56. pDevExt->ustrDeviceName = devName;
  57. //创建符号链接
  58. UNICODE_STRING symLinkName;
  59. RtlInitUnicodeString(&symLinkName,L"\\??\\HelloDDK");
  60. pDevExt->ustrSymLinkName = symLinkName;
  61. status = IoCreateSymbolicLink( &symLinkName,&devName );
  62. if (!NT_SUCCESS(status))
  63. {
  64. IoDeleteDevice( pDevObj );
  65. return status;
  66. }
  67. return STATUS_SUCCESS;
  68. }
  69. /************************************************************************
  70. * 函数名称:HelloDDKUnload
  71. * 功能描述:负责驱动程序的卸载操作
  72. * 参数列表:
  73. pDriverObject:驱动对象
  74. * 返回 值:返回状态
  75. *************************************************************************/
  76. #pragma PAGEDCODE
  77. VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject)
  78. {//遍历系统中所有的此类设备对象,删除设备对象及其符号链接
  79. PDEVICE_OBJECT    pNextObj;
  80. KdPrint(("Enter DriverUnload\n"));
  81. pNextObj = pDriverObject->DeviceObject;
  82. while (pNextObj != NULL)
  83. {
  84. PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
  85. pNextObj->DeviceExtension;
  86. //删除符号链接
  87. UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
  88. IoDeleteSymbolicLink(&pLinkName);
  89. pNextObj = pNextObj->NextDevice;
  90. IoDeleteDevice( pDevExt->pDevice );
  91. }
  92. }
  93. /************************************************************************
  94. * 函数名称:HelloDDKDispatchRoutine
  95. * 功能描述:对读IRP进行处理
  96. * 参数列表:
  97. pDevObj:功能设备对象
  98. pIrp:从IO请求包
  99. * 返回 值:返回状态
  100. *************************************************************************/
  101. #pragma PAGEDCODE
  102. NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj,
  103. IN PIRP pIrp)
  104. {
  105. KdPrint(("Enter HelloDDKDispatchRoutine\n"));
  106. NTSTATUS status = STATUS_SUCCESS;
  107. // 完成IRP
  108. pIrp->IoStatus.Status = status;
  109. pIrp->IoStatus.Information = 0;    // bytes xfered
  110. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
  111. KdPrint(("Leave HelloDDKDispatchRoutine\n"));
  112. return status;
  113. }

驱动虽然有了设备名称,但是这种设备名只能在内核态可见,而对于应用程序时不可见的。因此,驱动需要暴露一个符号链接,该链接指向真正的设备名称。
编译好生成的sys文件,我们可以使用 DriverMonitor 加载,加载->启动->停止->卸载。

6.再来看看WDM式驱动有什么不同。头文件就直接忽略了。
DriverEntry入口函数:

[cpp] view plaincopy
  1. /************************************************************************
  2. * 函数名称:DriverEntry
  3. * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
  4. * 参数列表:
  5. pDriverObject:从I/O管理器中传进来的驱动对象
  6. pRegistryPath:驱动程序在注册表的中的路径
  7. * 返回 值:返回初始化驱动状态
  8. *************************************************************************/
  9. #pragma INITCODE
  10. extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,
  11. IN PUNICODE_STRING pRegistryPath)
  12. {
  13. KdPrint(("Enter DriverEntry\n"));
  14. pDriverObject->DriverExtension->AddDevice = HelloWDMAddDevice;
  15. pDriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp;
  16. pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
  17. pDriverObject->MajorFunction[IRP_MJ_CREATE] =
  18. pDriverObject->MajorFunction[IRP_MJ_READ] =
  19. pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloWDMDispatchRoutine;
  20. pDriverObject->DriverUnload = HelloWDMUnload;
  21. KdPrint(("Leave DriverEntry\n"));
  22. return STATUS_SUCCESS;
  23. }

这里增加了一个设置AddDevice回调函数,此回调函数的作用是创建设备对象并由PNP(即插即用)管理器调用。并设置对IRP_MJ_PNP的IRP的回调函数。这都是NT和WDM驱动最大的不同点。而且在WDM驱动中,大部分卸载工作都不是由DriverUnload来处理,而是放在对IRP_MN_REMOVE_DEVICE的IRP的处理函数中处理。

下面是AddDevice回调函数的处理。

[cpp] view plaincopy
  1. /************************************************************************
  2. * 函数名称:HelloWDMAddDevice
  3. * 功能描述:添加新设备
  4. * 参数列表:
  5. DriverObject:从I/O管理器中传进来的驱动对象
  6. PhysicalDeviceObject:从I/O管理器中传进来的物理设备对象
  7. * 返回 值:返回添加新设备状态
  8. *************************************************************************/
  9. #pragma PAGEDCODE
  10. NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
  11. IN PDEVICE_OBJECT PhysicalDeviceObject)
  12. {
  13. PAGED_CODE();
  14. KdPrint(("Enter HelloWDMAddDevice\n"));
  15. NTSTATUS status;
  16. PDEVICE_OBJECT fdo;
  17. UNICODE_STRING devName;
  18. RtlInitUnicodeString(&devName,L"\\Device\\MyWDMDevice");
  19. status = IoCreateDevice(
  20. DriverObject,
  21. sizeof(DEVICE_EXTENSION),
  22. &(UNICODE_STRING)devName,
  23. FILE_DEVICE_UNKNOWN,
  24. 0,
  25. FALSE,
  26. &fdo);
  27. if( !NT_SUCCESS(status))
  28. return status;
  29. PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
  30. pdx->fdo = fdo;
  31. pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);
  32. UNICODE_STRING symLinkName;
  33. RtlInitUnicodeString(&symLinkName,L"\\DosDevices\\HelloWDM");
  34. pdx->ustrDeviceName = devName;
  35. pdx->ustrSymLinkName = symLinkName;
  36. status = IoCreateSymbolicLink(&(UNICODE_STRING)symLinkName,&(UNICODE_STRING)devName);
  37. if( !NT_SUCCESS(status))
  38. {
  39. IoDeleteSymbolicLink(&pdx->ustrSymLinkName);
  40. status = IoCreateSymbolicLink(&symLinkName,&devName);
  41. if( !NT_SUCCESS(status))
  42. {
  43. return status;
  44. }
  45. }
  46. fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
  47. fdo->Flags &= ~DO_DEVICE_INITIALIZING;
  48. KdPrint(("Leave HelloWDMAddDevice\n"));
  49. return STATUS_SUCCESS;
  50. }

其中PAGED_CODE是一个DDK提供的宏,只在check版中有效。当此例程所在的中断请求及超过APC_LEVEL时,会产生一个断言。

本例对IRP_MN_REMOVE_DEVICE的处理。

[cpp] view plaincopy
  1. /************************************************************************
  2. * 函数名称:HandleRemoveDevice
  3. * 功能描述:对IRP_MN_REMOVE_DEVICE IRP进行处理
  4. * 参数列表:
  5. fdo:功能设备对象
  6. Irp:从IO请求包
  7. * 返回 值:返回状态
  8. *************************************************************************/
  9. #pragma PAGEDCODE
  10. NTSTATUS HandleRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp)
  11. {
  12. PAGED_CODE();
  13. KdPrint(("Enter HandleRemoveDevice\n"));
  14. Irp->IoStatus.Status = STATUS_SUCCESS;
  15. NTSTATUS status = DefaultPnpHandler(pdx, Irp);
  16. IoDeleteSymbolicLink(&(UNICODE_STRING)pdx->ustrSymLinkName);
  17. //调用IoDetachDevice()把fdo从设备栈中脱开:
  18. if (pdx->NextStackDevice)
  19. IoDetachDevice(pdx->NextStackDevice);
  20. //删除fdo:
  21. IoDeleteDevice(pdx->fdo);
  22. KdPrint(("Leave HandleRemoveDevice\n"));
  23. return status;
  24. }

而对卸载例程的处理可以什么都不用做。

其他PNP的IRP如果不需要做处理,那么直接传递到底层驱动,并将底层驱动的结果返回。

[cpp] view plaincopy
  1. /************************************************************************
  2. * 函数名称:DefaultPnpHandler
  3. * 功能描述:对PNP IRP进行缺省处理
  4. * 参数列表:
  5. pdx:设备对象的扩展
  6. Irp:从IO请求包
  7. * 返回 值:返回状态
  8. *************************************************************************/
  9. #pragma PAGEDCODE
  10. NTSTATUS DefaultPnpHandler(PDEVICE_EXTENSION pdx, PIRP Irp)
  11. {
  12. PAGED_CODE();
  13. KdPrint(("Enter DefaultPnpHandler\n"));
  14. IoSkipCurrentIrpStackLocation(Irp);
  15. KdPrint(("Leave DefaultPnpHandler\n"));
  16. return IoCallDriver(pdx->NextStackDevice, Irp);
  17. }

安装WDM式驱动需要一个inf文件。inf文件描述了WDM驱动程序的操作硬件设备的信息和驱动程序的一些信息。
可以直接右击这个inf文件进行安装即可。

NT驱动程序和WDM驱动程序的区别相关推荐

  1. WINDOWS下PCI接口卡WDM驱动程序的DMA编程技术1

    摘要:     本文主要讨论了在Windows环境下开发PCI接口卡DMA应用的WDM编程技术,并给出了一个应用DriverWorks和VC++开发的实例程序代码. 关键词:Windows.PCI总线 ...

  2. WDM驱动程序入门(3)——安装步骤

    WDM驱动程序入门(3)--安装步骤 DDK分为98 DDK和2000 DDK两种,它们工作起来是大同小异的,不过有些驱动程序只能在2000 DDK中使用.由于Win98注定是一种即将被淘汰的操作系统 ...

  3. WDM 驱动程序开发

    1.概述  引入了全新的WDM (Win32 Driver Model)的驱动程序架构,说是新技术,其实早在1997年Microsoft就提出了该项技术并在Windows 98中得到了充分的应用,换句 ...

  4. WDM驱动程序入门(很详细)

    WDM驱动程序是一种很新的东西,相信很多人都跟我一样,对它很感兴趣,但是又找不到学习的切入点.究其原因,还是因为WDM是一种非常"死板板"的程序,它一运行就是工作在系统的底层RIN ...

  5. WDM驱动程序入门(1)-Hello WDM

    WDM驱动程序入门(1)-Hello WDM     WDM驱动程序是一种很新的东西,相信很多人都跟我一样,对它很感兴趣,但是又找不到学习的切入点.究其原因,还是因为WDM是一种非常"死板板 ...

  6. WDM驱动程序介绍(引)

    http://zhidao.baidu.com/question/56715021.html WDM(Windows driver model)是微软为开发人员提供的一种编写运行在Windows平台下 ...

  7. 图形驱动程序和显卡驱动什么区别_我们常说的计算机驱动程序到底是什么,深入解读驱动程序本质...

    设备驱动程序通常又被称为设备处理程序,是I/O进程与设备控制器之间的通信程序,主要任务是接受上层软件发来的抽象I/O要求.将它转化为具体要求后,发送给设备控制器,启动设备去执行,也会将设备控制器发来的 ...

  8. VxWorks设备驱动程序开发指南---驱动程序的分类

    8D Spaces Reliability & Stability & Efficiency 目录视图 摘要视图 订阅 VxWorks设备驱动程序开发指南(三)---驱动程序的分类 2 ...

  9. VxWorks驱动程序开发指南--驱动程序的组织结构

    8D Spaces Reliability & Stability & Efficiency 目录视图 摘要视图 订阅 VxWorks驱动程序开发指南(四)--驱动程序的组织结构 20 ...

  10. USB转WIFI无线网卡驱动程序(RT5370驱动程序)的移植记录之一

    学习交流加 个人qq: 1126137994 个人微信: liu1126137994 学习交流资源分享qq群: 962535112 今天记录我在I.MX6Q平台移植RT5370无线网卡驱动程序的过程, ...

最新文章

  1. ProxylessNAS pytorch
  2. 对的调用没有匹配的函数_前端开发之——函数、事件、js对象
  3. ubuntu vim php配置文件在哪,ubuntu vim的配置文件在哪
  4. suitecrm配置(nginx设置)
  5. django的admin
  6. 聚合直播源码原生播放器php分享,原生聚合直播搭建源码
  7. Linux驱动——设备树
  8. DirectX、Directshow介绍
  9. 服务器SQL上的MSDTC不可用解决办法
  10. 年终盘点丨2021边缘计算大事记
  11. 第八届山东省ACM大学生程序设计竞赛总结
  12. 【回溯】B033_LQ_填字母游戏(暴搜+注意参数传递机制)
  13. Winform:自定义滚动条——可自定义皮肤
  14. 用SVD压缩彩色图片(MATLAB代码)
  15. 在计算机小三号是多少在英语,计算机的一些常用英语。
  16. 台式计算机的内存容量,内存容量
  17. 新手nvm npm 卸载不用依赖包,项识别为 cmdlet、函数、脚本文件,等命令集合
  18. 【Allegro_SPB_16.6安装详细教程】手把手搭建到Win10
  19. poky: qmmp_0.5.2.bb的问题以及修改方法。
  20. 2023新年红包,兔年HTML红包页面代码【2023新年快乐_附源码】

热门文章

  1. js/vue 动态获取浏览器宽度/高度
  2. android多个单选框超格,福昕PDF阅读器打印时提示“打印机被意外删除了”怎么处理?...
  3. GBT9706.1中B型BF型和CF型各表示什么意思?多参监护仪设计
  4. 《硬件接入》海康威视接入及CPU性能优化思路
  5. 800元以内创建的双路CPU主机
  6. aes简单文本加密工具
  7. 金蝶K3 各个表对应的名称
  8. u8文件服务器在哪设置,u8 设置文件服务器
  9. ssh远程连接服务器常用命令
  10. python调用windows aplication