• 15、Windows驱动开发技术详解笔记(11) 基本概念


    9Windows驱动程序的入口函数规定为_DriverEntry@8,所以用C++编写时要用extern

    驱动程序中,不能使用编译器运行时函数,甚至C语言中的malloc,C++new函数都不能用,因为他们在VC中的实现都是调用了Win32 API了。要用的话,必须自己重载new等运算符。大部分运行时函数是通过Win32 API实现的。在内核模式下无法调用用户模式的程序,而用户模式下通过参数审核可以调用内核态程序。

    内核态的运行时函数来替换用户态的运行时函数,一般形如RtlXXXX

    设备名称用UNICODE字符串指定,且必须是“\Device\[设备名]”形式。用户模式下,通过两种方法找到设备:

    1:符号连接

    2:通过设备接口。

    一般虚拟设备用FILE_DEVICE_UNKNOWN类型。

    ******************

    "采用C++编程,所以需要用extern "C",因为我们导入的是C的函数的符号表",系统内核是有C语言编写的,连接时要调用相应的函数,所以应当把驱动头文件编译成C语言形式。

    10、用build编译

    Build首先设置环境变量,然后调用nmakenmake解析makefile,调用cl,link来编译程序。

    Makefile中依赖关系如下声明:

    ABC

    Action

    说明:A依赖于BC。如果A的最后修改时间早于BC任一个文件的最后修改时间,则执行actionAction前面是tab

    VC编译,我们在另一篇中论述。

    11、查看调试信息

    法一:打印信息

    尽量用KdPrint,free版本中不显示。同prrinf使用,双括号,宽字符用%ws%S

    法二:用DriverStudio中的DriverMonitor。不过可以用免费的DbgView,下载地址是:

    http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx

    12、加载驱动

    NT式驱动程序的加载,是基本服务的方式加载的。设备驱动程序的动态加载主要由服务控制管理程序(SCM)系统组件完成的。Windows服务应用程序遵循控制管理器。Driver ServiceWindows服务的一个特例,它遵守Windows服务的协议。

    wps_clip_image-28690

    图 加载 P72

    wps_clip_image-15815

    图 卸载驱动流程 P72

    代码 加载和卸载驱动代码

    代码
    1 #include <windows.h>
    2 #include <winsvc.h>
    3 #include <conio.h>
    4 #include <stdio.h>
    5
    6  #define DRIVER_NAME "HelloDDK"
    7  #define DRIVER_PATH "..\\MyDriver\\MyDriver_Check\\HelloDDK.sys"
    8
    9 //装载NT驱动程序
    10 BOOL LoadNTDriver(char* lpszDriverName,char* lpszDriverPath)
    11 {
    12 char szDriverImagePath[256];
    13 //得到完整的驱动路径
    14 GetFullPathName(lpszDriverPath, 256, szDriverImagePath, NULL);
    15
    16 BOOL bRet = FALSE;
    17
    18 SC_HANDLE hServiceMgr=NULL;//SCM管理器的句柄
    19 SC_HANDLE hServiceDDK=NULL;//NT驱动程序的服务句柄
    20
    21 //打开服务控制管理器
    22 hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
    23
    24 if( hServiceMgr == NULL )
    25 {
    26 //OpenSCManager失败
    27 printf( "OpenSCManager() Faild %d ! \n", GetLastError() );
    28 bRet = FALSE;
    29 goto BeforeLeave;
    30 }
    31 else
    32 {
    33 ////OpenSCManager成功
    34 printf( "OpenSCManager() ok ! \n" );
    35 }
    36
    37 //创建驱动所对应的服务
    38 hServiceDDK = CreateService( hServiceMgr,
    39 lpszDriverName, //驱动程序的在注册表中的名字
    40 lpszDriverName, // 注册表驱动程序的 DisplayName 值
    41 SERVICE_ALL_ACCESS, // 加载驱动程序的访问权限
    42 SERVICE_KERNEL_DRIVER,// 表示加载的服务是驱动程序
    43 SERVICE_DEMAND_START, // 注册表驱动程序的 Start 值
    44 SERVICE_ERROR_IGNORE, // 注册表驱动程序的 ErrorControl 值
    45 szDriverImagePath, // 注册表驱动程序的 ImagePath 值
    46 NULL,
    47 NULL,
    48 NULL,
    49 NULL,
    50 NULL);
    51
    52 DWORD dwRtn;
    53 //判断服务是否失败
    54 if( hServiceDDK == NULL )
    55 {
    56 dwRtn = GetLastError();
    57 if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_EXISTS )
    58 {
    59 //由于其他原因创建服务失败
    60 printf( "CrateService() Faild %d ! \n", dwRtn );
    61 bRet = FALSE;
    62 goto BeforeLeave;
    63 }
    64 else
    65 {
    66 //服务创建失败,是由于服务已经创立过
    67 printf( "CrateService() Faild Service is ERROR_IO_PENDING or ERROR_SERVICE_EXISTS! \n" );
    68 }
    69
    70 // 驱动程序已经加载,只需要打开
    71 hServiceDDK = OpenService( hServiceMgr, lpszDriverName, SERVICE_ALL_ACCESS );
    72 if( hServiceDDK == NULL )
    73 {
    74 //如果打开服务也失败,则意味错误
    75 dwRtn = GetLastError();
    76 printf( "OpenService() Faild %d ! \n", dwRtn );
    77 bRet = FALSE;
    78 goto BeforeLeave;
    79 }
    80 else
    81 {
    82 printf( "OpenService() ok ! \n" );
    83 }
    84 }
    85 else
    86 {
    87 printf( "CrateService() ok ! \n" );
    88 }
    89
    90 //开启此项服务
    91 bRet= StartService( hServiceDDK, NULL, NULL );
    92 if( !bRet )
    93 {
    94 DWORD dwRtn = GetLastError();
    95 if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_ALREADY_RUNNING )
    96 {
    97 printf( "StartService() Faild %d ! \n", dwRtn );
    98 bRet = FALSE;
    99 goto BeforeLeave;
    100 }
    101 else
    102 {
    103 if( dwRtn == ERROR_IO_PENDING )
    104 {
    105 //设备被挂住
    106 printf( "StartService() Faild ERROR_IO_PENDING ! \n");
    107 bRet = FALSE;
    108 goto BeforeLeave;
    109 }
    110 else
    111 {
    112 //服务已经开启
    113 printf( "StartService() Faild ERROR_SERVICE_ALREADY_RUNNING ! \n");
    114 bRet = TRUE;
    115 goto BeforeLeave;
    116 }
    117 }
    118 }
    119 bRet = TRUE;
    120 //离开前关闭句柄
    121 BeforeLeave:
    122 if(hServiceDDK)
    123 {
    124 CloseServiceHandle(hServiceDDK);
    125 }
    126 if(hServiceMgr)
    127 {
    128 CloseServiceHandle(hServiceMgr);
    129 }
    130 return bRet;
    131 }
    132
    133 //卸载驱动程序
    134 BOOL UnloadNTDriver( char * szSvrName )
    135 {
    136 BOOL bRet = FALSE;
    137 SC_HANDLE hServiceMgr=NULL;//SCM管理器的句柄
    138 SC_HANDLE hServiceDDK=NULL;//NT驱动程序的服务句柄
    139 SERVICE_STATUS SvrSta;
    140 //打开SCM管理器
    141 hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
    142 if( hServiceMgr == NULL )
    143 {
    144 //带开SCM管理器失败
    145 printf( "OpenSCManager() Faild %d ! \n", GetLastError() );
    146 bRet = FALSE;
    147 goto BeforeLeave;
    148 }
    149 else
    150 {
    151 //带开SCM管理器失败成功
    152 printf( "OpenSCManager() ok ! \n" );
    153 }
    154 //打开驱动所对应的服务
    155 hServiceDDK = OpenService( hServiceMgr, szSvrName, SERVICE_ALL_ACCESS );
    156
    157 if( hServiceDDK == NULL )
    158 {
    159 //打开驱动所对应的服务失败
    160 printf( "OpenService() Faild %d ! \n", GetLastError() );
    161 bRet = FALSE;
    162 goto BeforeLeave;
    163 }
    164 else
    165 {
    166 printf( "OpenService() ok ! \n" );
    167 }
    168 //停止驱动程序,如果停止失败,只有重新启动才能,再动态加载。
    169 if( !ControlService( hServiceDDK, SERVICE_CONTROL_STOP , &SvrSta ) )
    170 {
    171 printf( "ControlService() Faild %d !\n", GetLastError() );
    172 }
    173 else
    174 {
    175 //打开驱动所对应的失败
    176 printf( "ControlService() ok !\n" );
    177 }
    178 //动态卸载驱动程序。
    179 if( !DeleteService( hServiceDDK ) )
    180 {
    181 //卸载失败
    182 printf( "DeleteSrevice() Faild %d !\n", GetLastError() );
    183 }
    184 else
    185 {
    186 //卸载成功
    187 printf( "DelServer:eleteSrevice() ok !\n" );
    188 }
    189 bRet = TRUE;
    190 BeforeLeave:
    191 //离开前关闭打开的句柄
    192 if(hServiceDDK)
    193 {
    194 CloseServiceHandle(hServiceDDK);
    195 }
    196 if(hServiceMgr)
    197 {
    198 CloseServiceHandle(hServiceMgr);
    199 }
    200 return bRet;
    201 }
    202
    203 void TestDriver()
    204 {
    205 //测试驱动程序
    206 HANDLE hDevice = CreateFile("\\\\.\\HelloDDK",
    207 GENERIC_WRITE | GENERIC_READ,
    208 0,
    209 NULL,
    210 OPEN_EXISTING,
    211 0,
    212 NULL);
    213 if( hDevice != INVALID_HANDLE_VALUE )
    214 {
    215 printf( "Create Device ok ! \n" );
    216 }
    217 else
    218 {
    219 printf( "Create Device faild %d ! \n", GetLastError() );
    220 }
    221 CloseHandle( hDevice );
    222 }
    223
    224 int main(int argc, char* argv[])
    225 {
    226 //加载驱动
    227 BOOL bRet = LoadNTDriver(DRIVER_NAME,DRIVER_PATH);
    228 if (!bRet)
    229 {
    230 printf("LoadNTDriver error\n");
    231 return 0;
    232 }
    233 //加载成功
    234
    235 printf( "press any to create device!\n" );
    236 getch();
    237
    238 TestDriver();
    239
    240 //这时候你可以通过注册表,或其他查看符号连接的软件验证。
    241 printf( "press any to unload the driver!\n" );
    242 getch();
    243
    244 //卸载驱动
    245 UnloadNTDriver(DRIVER_NAME);
    246 if (!bRet)
    247 {
    248 printf("UnloadNTDriver error\n");
    249 return 0;
    250 }
    251
    252 return 0;
    253 }
    254
    255

    关于WDM驱动的手工加载,见[1]

    13NT驱动程序的基本结构

    1)数据结构

    DEVICE_OBJECT

    The DEVICE_OBJECT structure is used by the operating system to represent a device object. A device object represents a logical, virtual, or physical device for which a driver handles I/O requests.

    http://msdn.microsoft.com/en-us/library/ff543147%28VS.85%29.aspx

    每个设备对象指针指向向一个设备对象,最后一个设备对象指向空。

    wps_clip_image-28693

    图 设备对象布局图 P92

    设备扩展对象定义自己定义的结构体,驱动程序中尽是避免使用全局变量,因为会影响同步,而把全局变量存在设备扩展里。

    driver object

    Each driver object represents the image of a loaded kernel-mode driver. A pointer to the driver object is an input parameter to a driver's DriverEntry, AddDevice, and optional Reinitialize routines and to its Unload routine, if any.

    每个驱动程序与唯一的驱动对象相对应,这个驱动对象是在驱动加载时候,被内核中的对象管理器创建。驱动对象为驱动和个实例被内核加载,并且一个驱动只能加载一个实例。

    wps_clip_image-26564

    图 驱动对象布局图 P88

    其它参见:

    http://www.cnblogs.com/mydomain/archive/2010/10/16/1853235.html

    14DriverEntry主要是对系统进程创建的驱动对象进行初始化。

    15WDM程序的基本结构

    一般都是基于分层的,完成一个设备的操作,至少要由两个驱动设备共同完成。一个是PDO(物理设备对象),一个是FDO(功能设备对象),其关系是附加与被附加关系。当PC中插入某个设备时,总线驱动自动创建PDO,由PDO引出FDO

    wps_clip_image-5558

    FDOPDO P103

    过滤驱动不是必须的。

    NT的不同:

    · 增加了对AddDevice函数的设备。操作系统加载PDO后,调用驱动的AddDevice例程,AddDevice例程负责创建FDO,并且附加到PDO之上。

    ·设备对象在AddDevice例程中创建。

    ·必须加入IRP_MJ_PNP的派遣回调函数。

    PDO会通过AttachedDevice子域知道它上面的设备是FDO或过滤驱动,但是不知道下面的,可以通过定制自己的设备扩展来记录地址。

    16、设备的层次结构

    wps_clip_image-24338

    图 设备对象堆栈 P104

    wps_clip_image-4820

    图 垂直结构 P111,P113

    参考

    1Windows 驱动开发技术详解

    2http://msdn.microsoft.com/en-us/library/ff565757%28VS.85%29.aspx
    3Windows驱动学习笔记,灰狐

  • 相关阅读:
    07_Go语言 ( 切片)
    06_Go语言( 数组)
    05_Go语言( 流程控制)
    04_Go语言( 运算符)
    02_Go语言(变量和常量)
    01_Go语言(环境的搭建)
    云电脑直播简单指南
    统信UOS共享打印机配置
    #插头dp#洛谷 5074 Eat the Trees
    #状压dp#洛谷 3959 [NOIP2017 提高组] 宝藏
  • 原文地址:https://www.cnblogs.com/mydomain/p/1859572.html
Copyright © 2020-2023  润新知