﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-canmeng50401的专栏-文章分类-windows驱动开发技术详解 笔记</title><link>http://www.cppblog.com/canmeng50401/category/17003.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 24 Jun 2011 12:28:36 GMT</lastBuildDate><pubDate>Fri, 24 Jun 2011 12:28:36 GMT</pubDate><ttl>60</ttl><item><title>第5章 Windows内存管理</title><link>http://www.cppblog.com/canmeng50401/articles/chapter5.html</link><dc:creator>纪灿萌</dc:creator><author>纪灿萌</author><pubDate>Mon, 20 Jun 2011 15:26:00 GMT</pubDate><guid>http://www.cppblog.com/canmeng50401/articles/chapter5.html</guid><wfw:comment>http://www.cppblog.com/canmeng50401/comments/149066.html</wfw:comment><comments>http://www.cppblog.com/canmeng50401/articles/chapter5.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/canmeng50401/comments/commentRss/149066.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/canmeng50401/services/trackbacks/149066.html</trackback:ping><description><![CDATA[<p>P119 Windows的所有程序(包括Ring0和Ring3层的程序)可以操作的都是虚拟内存。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4GB的虚拟内存会被分割成1M个(2<sup>20</sup>个)页，每个页的大小为4KB(2<sup>12</sup>个字节)。其中，有一部分单元会和物理内存对应起来；还有一部分单元会被映射成磁盘上的文件；还有一部分单元什么也没有对应，即空的。<br />P120 Windows操作系统在进程切换时，保持内核模式地址是完全相同的。也就是说，所有进程的内核地址映射完全一致，进程切换的时候，只改变用户模式地址的映射。<br />P121 驱动程序可以看成是一个特殊的DLL文件被应用程序加载到虚拟内存中，只不过加载地址是内核模式地址，而不是用户模式地址，它能访问的只是这个进程的虚拟内存，而不是其它进程的虚拟内存。<span style="color: #ff0000" mce_style="color: #ff0000;">需要指出的是，Windows驱动程序里的不同例程运行在不同的进程中</span>。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用如下代码可以看出当前代码运行在哪个进程的上下文中：</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #000000">VOID&nbsp;DisplayItsProcessName()<br /><img id="Codehighlighter1_29_185_Open_Image" onclick="this.style.display='none'; Codehighlighter1_29_185_Open_Text.style.display='none'; Codehighlighter1_29_185_Closed_Image.style.display='inline'; Codehighlighter1_29_185_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_29_185_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_29_185_Closed_Text.style.display='none'; Codehighlighter1_29_185_Open_Image.style.display='inline'; Codehighlighter1_29_185_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_29_185_Closed_Text"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_29_185_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">得到当前进程</span><span style="color: #008000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;PEPROCESS&nbsp;peProcess&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;PsGetCurrentProcess();<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">得到当前进程名称</span><span style="color: #008000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;PTSTR&nbsp;ProcessName&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(PTSTR)((ULONG)peProcess&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0x174</span><span style="color: #000000">);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;KdPrint((</span><span style="color: #000000">"</span><span style="color: #000000">%s</span><span style="color: #000000">"</span><span style="color: #000000">,ProcessName));<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span></div>
<p>P122 Windows规定有些虚拟内存页面是可以交换到文件中的，这类内存被称为分页内存；而有些虚拟内存永远不会交换到文件中，这些内存被称为非分页内存。<br />P124 双向链表(这个数据结构在程序中常常用到，比较重要)<br />P140 LARGE_INTEGER数据结构的定义。这个结构也常常用到，很重要。</p>
<p><br />&nbsp;</p><img src ="http://www.cppblog.com/canmeng50401/aggbug/149066.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/canmeng50401/" target="_blank">纪灿萌</a> 2011-06-20 23:26 <a href="http://www.cppblog.com/canmeng50401/articles/chapter5.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第4章 驱动程序的基本结构</title><link>http://www.cppblog.com/canmeng50401/articles/chapter4.html</link><dc:creator>纪灿萌</dc:creator><author>纪灿萌</author><pubDate>Sun, 19 Jun 2011 15:59:00 GMT</pubDate><guid>http://www.cppblog.com/canmeng50401/articles/chapter4.html</guid><wfw:comment>http://www.cppblog.com/canmeng50401/comments/148997.html</wfw:comment><comments>http://www.cppblog.com/canmeng50401/articles/chapter4.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/canmeng50401/comments/commentRss/148997.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/canmeng50401/services/trackbacks/148997.html</trackback:ping><description><![CDATA[<p>P87 每个驱动程序会有唯一的驱动对象与之对应，并且这个驱动对象是在驱动加载的时候，被内核中的对象管理程序创建的。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #ff0000" mce_style="color: #ff0000;">驱动对象用DRIVER_OBJECT数据结构表示</span>，它作为驱动的一个实例被内核加载(准确的说，是由内核中的I/O管理器负责加载的)，并且内核对一个驱动只加载一个实例。<br />P89 每个驱动程序都会创建一个或多个<span style="color: #ff0000" mce_style="color: #ff0000;">设备对象，用DEVICE_OBJECT数据结构表示</span>。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AttachedDevice：是一个指针，指向附加在自身上面的一个上层设备对象。也就是说，如果有更高一层的设备对象附加在自身设备对象的时候，AttachedDevice指向的就是那个高一层的设备对象。<span style="color: #ff0000" mce_style="color: #ff0000;">如P<sub>103</sub>中，当一个FDO附加在PDO上的时候，PDO设备对象的子域AttachedDevice会记录FDO的位置</span>。<br />P90 在驱动程序中，应该尽量避免全局变量的使用，因为全局变量设计不容易同步的问题。解决的办法：将全局变量存在设备扩展中。<br />P91 设备扩展是由程序员指定内容和大小，由I/O管理器创建的，并保存在非分页内存中。<br />P93 DriverEntry主要是对驱动程序进行初始化工作，它是由系统进程所调用的。<br />P95 让用户模式下的应用程序能识别设有两种方法，一是通过符号链接找到设备，二是通过设备接口找到设备。<br />P96 在内核模式下，符号链接是以"\??\"开头的(或者是以"\DosDevices\"开头的)。而在用户模式下，则是以"\\.\"开头的。<br />P102 在WDM模型中，完成一个设备的操作，至少有两个设备对象共同完成。一个是物理设备对象(Physical Device Object,简称PDO)，另一个是功能设备对象(Function Device Object,简称FDO)。<br />WDM驱动和NT驱动的区别有：<br />1.&nbsp; P104 NT式驱动中，创建设备对象是在DriverEntry中实现的。而WDM驱动中，创建设备对象不在DriverEntry中，而是放在了AddDevice例程中。<br />2.&nbsp;&nbsp;P104 WDM驱动中，在DriverEntry中，需要设置对IRP_MJ_PNP处理的派遣函数。而NT式驱动中不需要。<br />3.&nbsp; P107 NT式驱动中，DriverUnload例程主要负责做删除设备和取消符号链接的工作。而在WDM驱动中，这部分操作被IRP_MN_REMOVE_DEVICE的处理函数所负责。<br />&nbsp;&nbsp;&nbsp;&nbsp; P108 在IRP_MN_REMOVE_DEVICE的处理函数中，除了删除设备和取消符号链接外，在此函数中还需要使用函数IoDetachDevice函数将FDO从PDO的堆栈中&#8220;摘除&#8221;下来。<br />P114 两个小程序</p><img src ="http://www.cppblog.com/canmeng50401/aggbug/148997.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/canmeng50401/" target="_blank">纪灿萌</a> 2011-06-19 23:59 <a href="http://www.cppblog.com/canmeng50401/articles/chapter4.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第3章 Windows驱动编译环境配置、安装及调试</title><link>http://www.cppblog.com/canmeng50401/articles/chapter3.html</link><dc:creator>纪灿萌</dc:creator><author>纪灿萌</author><pubDate>Sat, 18 Jun 2011 11:45:00 GMT</pubDate><guid>http://www.cppblog.com/canmeng50401/articles/chapter3.html</guid><wfw:comment>http://www.cppblog.com/canmeng50401/comments/148926.html</wfw:comment><comments>http://www.cppblog.com/canmeng50401/articles/chapter3.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/canmeng50401/comments/commentRss/148926.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/canmeng50401/services/trackbacks/148926.html</trackback:ping><description><![CDATA[<p>P51 在VC编译器中，默认使用C语言的调用约定。而在Windows驱动程序的编写中，需要使用标准调用约定，尤其是入口函数。<br />P52 默认情况下，编译器会根据源文件的扩展名，来判断使用哪种方式编译。扩展名是.cpp时，使用C++方式编译；扩展名是.c时，使用C编译器方式编译。<br />P53 Windows操作系统规定，在内核模式的程序是无法调用用户模式的程序的，而用户模式的程序可以调用内核模式下的程序(这需要严格的参数审查)。<br />P57 其实不管是build工具、nmake工具、还是VC集成开发环境，最终调用的都是cl.exe(编译器)和link.exe(链接器)，所以其原理都是大体相同的。<br />P68 编写程序加载NT式驱动</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 加载步骤：(1)打开SCM管理器；(2)创建服务；(3)启动服务；(4)关闭服务；(5)关闭SCM管理器。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 卸载步骤：(1)打开SCM管理器；(2)打开服务；(3)暂停服务；(4)删除服务；(5)关闭服务；(6)关闭SCM管理器。<br />实际上，windows DDK中提供的sample中有关于安装NT式驱动的代码。那里面的代码应该写的比较好吧。<br />P81 WDM式驱动程序的安装会在三个方面修改注册表，分别是硬件子键(Hardware)、类子键(Class)、服务子键(Service)。</p><img src ="http://www.cppblog.com/canmeng50401/aggbug/148926.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/canmeng50401/" target="_blank">纪灿萌</a> 2011-06-18 19:45 <a href="http://www.cppblog.com/canmeng50401/articles/chapter3.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第2章 Windows操作驱动的基本概念</title><link>http://www.cppblog.com/canmeng50401/articles/chapter2.html</link><dc:creator>纪灿萌</dc:creator><author>纪灿萌</author><pubDate>Sat, 18 Jun 2011 11:16:00 GMT</pubDate><guid>http://www.cppblog.com/canmeng50401/articles/chapter2.html</guid><wfw:comment>http://www.cppblog.com/canmeng50401/comments/148922.html</wfw:comment><comments>http://www.cppblog.com/canmeng50401/articles/chapter2.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/canmeng50401/comments/commentRss/148922.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/canmeng50401/services/trackbacks/148922.html</trackback:ping><description><![CDATA[P33 线程运行在自己的线程上下文中。线程上下文指的是CPU寄存器的状态，比如堆栈寄存器、指令寄存器等，还包括线程ID、线程的优先级、线程的本地存储等线程相关的信息。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 内核的主要作用是调度线程活动，而操作系统的其它组件，<span style="color: #ff0000" mce_style="color: #ff0000;">如内存管理组件、进程管理组件等作为独立于内核的组件，统称为执行程序组件(或者成为执行体组件)</span>。<br />P34 Windows从总体上分为内核模式(Kernel Mode)和用户模式(User Mode)。谈到操作系统的内核模式和用户模式，一般会和CPU的特权层联系起来。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ring0和Ring3层是CPU上的概念，而用户模式和内核模式是操作系统上的概念。<br />P35 编写驱动程序主要是为了操作硬件设备。对硬件设备的操作包括访问物理映射内存、设备端口等。<br />P38 图2-6 Windows架构简图<br />P41 从用户模式进入到内核模式，是通过软中断的方式进入的。<br />P42 执行程序组件又可以细分为若干个组件：1.对象管理程序；2.进程管理程序；3.虚拟内存管理程序；4.I/O管理器；5.配置管理程序<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对象管理程序就是创建、管理、回收对象的组件。在驱动程序开发中，设计很多的对象，如驱动程序对象(Driver Object)、设备对象(Device Object)等。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;进程管理程序负责创建和终止进程，线程的调度是由内核负责的。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 虚拟内存管理程序是负责对虚拟内存进行管理的组件。对虚拟内存的申请、回收等操作都是由该组件实现的。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; I/O管理器负责发起I/O请求，并且管理这些请求。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 配置管理程序负责记录计算机中所有软件和硬件的配置信息。它使用注册表保存这些数据。<br />P43 Windows规定，将4GB的虚拟内存分成两个部分。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另外，Windows规定所有进程内核模式下的虚拟内存的映射方式完全一样。<br />P46 Windows的设计者们为了简化对不同设备的操作，实现对不同设备统一接口，将所有设备当作普通文件看待。也就是说在Windows中，无论何种设备，都用操作文件的方法去操作设备。<img src ="http://www.cppblog.com/canmeng50401/aggbug/148922.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/canmeng50401/" target="_blank">纪灿萌</a> 2011-06-18 19:16 <a href="http://www.cppblog.com/canmeng50401/articles/chapter2.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第1章 从两个最简单的驱动谈起</title><link>http://www.cppblog.com/canmeng50401/articles/chapter1.html</link><dc:creator>纪灿萌</dc:creator><author>纪灿萌</author><pubDate>Sat, 18 Jun 2011 10:28:00 GMT</pubDate><guid>http://www.cppblog.com/canmeng50401/articles/chapter1.html</guid><wfw:comment>http://www.cppblog.com/canmeng50401/comments/148920.html</wfw:comment><comments>http://www.cppblog.com/canmeng50401/articles/chapter1.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/canmeng50401/comments/commentRss/148920.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/canmeng50401/services/trackbacks/148920.html</trackback:ping><description><![CDATA[<p>P3 Windows驱动程序分为两类，一类是不支持即插即用功能的NT式驱动程序，另一类是支持即插即用功能的WDM式驱动程序。<br />P4 NT式驱动程序要导入的头文件是NTDDK.h，而WDM式的驱动程序要导入的头文件是WDM.h。<br />P5 因为这里采用C++语言编写，如果直接包含NTDDK.h，函数的符号表会导入错误，所以需要加入extern "C"，这样可以保证符号表正确导入。<br />&nbsp;&nbsp;&nbsp;&nbsp; DriverEntry函数由内核中的I/O管理器负责调用。<br />P6 KdPrint其实是一个宏，在调试版本(Checked版)中，会用DbgPrint代替。而在发行版(Free版)中，则不执行任何操作，其功能类似于MFC中的TRACE宏。<br />P8 驱动程序虽然有了设备名称，但是这种设备名称只能在内核态可见，而对于应用程序是不可见的。因此，驱动需要暴露一个符号链接，应用程序可以通过这个符号链接来访问设备。<br />P14 NT式驱动程序类似于Windows服务程序，以服务的形式加载在系统中。<br />P18 AddDevice回调函数的作用是创建设备对象，而且这个回调函数是由PNP(即插即用)管理器调用的。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在WDM驱动程序中，大部分的卸载工作是在对IRP_MN_REMOVE_DEVICE这个IRP的处理函数中进行的。<br />P20,22 PAGED_CODE是一个DDK提供的宏，只在Checked版中有效。用PAGED_CODE宏确保该例程运行在低于APC_LEVEL的中断优先级的级别上。<br />P25 inf文件描述了WDM驱动程序的操作硬件设备的信息和驱动程序的一些信息。<br /><span style="color: #ff0000" mce_style="color: #ff0000;">注：<br /></span>P20中的 static NTSTATUS (*fcntab[])(PDEVICE_EXTENSION pdx, PIRP Irp)={&#8230;&#8230;}表示声明了一个指针数组，数组中的每一个元素都是一个指向函数的指针，函数又两个参数，函数的返回值是NTSTATUS状态值。<br />P21 fcnname[]数组中的这些IRP是在wdm.h中定义好的。<br />暂时不明白的地方：P4中的data_seg("INIT")是啥意思？P5中什么叫符号表导入？</p><img src ="http://www.cppblog.com/canmeng50401/aggbug/148920.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/canmeng50401/" target="_blank">纪灿萌</a> 2011-06-18 18:28 <a href="http://www.cppblog.com/canmeng50401/articles/chapter1.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>