<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>CLR &amp; Silverlight上海研发团队的Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/silverlightshanghai/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/silverlightshanghai/feed.xml</link>
    <description>专注底层技术</description>
    <lastBuildDate>Tue, 16 Apr 2019 05:48:54 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>本博客停止更新公告</title>
      <link>https://docs.microsoft.com/archive/blogs/silverlightshanghai/23</link>
      <pubDate>Sun, 13 Dec 2009 03:47:00 GMT</pubDate>
      <dc:creator><![CDATA[SilverlightShanghai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/silverlightshanghai/2009/12/13/23/</guid>
      <description><![CDATA[微软中国研发集团服务器与开发工具事业部近期调整了个别研发项目，我们希望专注于创新，并不断加深在部分产品和技术开发上的广度和深度。CLR/Silverlight小组所负责的Interop和JIT项目将近...]]></description>
      <content:encoded><![CDATA[<P style="MARGIN: 0in 0in 0pt" class=MsoNormal mce_style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-FAMILY: '微软雅黑','sans-serif'; FONT-SIZE: 10pt" mce_style="FONT-FAMILY: '微软雅黑','sans-serif'; FONT-SIZE: 10pt"><A href="https://blogs.msdn.com/stbcblog/" mce_href="https://blogs.msdn.com/stbcblog/"><SPAN lang=ZH-CN><FONT color=#0000ff>微软中国研发集团服务器与开发工具事业部</FONT></SPAN></A><SPAN lang=ZH-CN>近期调整了个别研发项目，我们希望专注于创新，并不断加深在部分产品和技术开发上的广度和深度。</SPAN>CLR/Silverlight<SPAN lang=ZH-CN>小组所负责的</SPAN>Interop<SPAN lang=ZH-CN>和</SPAN>JIT<SPAN lang=ZH-CN>项目将近期移交给美国团队，所有工程师也将于近期转入事业部其他的大项目组，这也意味着我们从即日起挥别这个耕耘了三年的中文博客。</SPAN><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P>
<P style="MARGIN: 0in 0in 0pt" class=MsoNormal mce_style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-FAMILY: '微软雅黑','sans-serif'; FONT-SIZE: 10pt" mce_style="FONT-FAMILY: '微软雅黑','sans-serif'; FONT-SIZE: 10pt"><o:p>&nbsp;</o:p></SPAN></P>
<P style="MARGIN: 0in 0in 0pt" class=MsoNormal mce_style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-FAMILY: '微软雅黑','sans-serif'; FONT-SIZE: 10pt" lang=ZH-CN mce_style="FONT-FAMILY: '微软雅黑','sans-serif'; FONT-SIZE: 10pt">如果您对</SPAN><SPAN style="FONT-FAMILY: '微软雅黑','sans-serif'; FONT-SIZE: 10pt" mce_style="FONT-FAMILY: '微软雅黑','sans-serif'; FONT-SIZE: 10pt">CLR<SPAN lang=ZH-CN>相关的内容感兴趣，请访问美国团队的博客：</SPAN><A href="https://blogs.msdn.com/clrteam/" mce_href="https://blogs.msdn.com/clrteam/"><FONT color=#0000ff>https://blogs.msdn.com/clrteam/</FONT></A><SPAN lang=ZH-CN>。</SPAN><o:p></o:p></SPAN></P>
<P style="MARGIN: 0in 0in 0pt" class=MsoNormal mce_style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-FAMILY: '微软雅黑','sans-serif'; FONT-SIZE: 10pt" mce_style="FONT-FAMILY: '微软雅黑','sans-serif'; FONT-SIZE: 10pt"><o:p>&nbsp;</o:p></SPAN></P>
<P style="MARGIN: 0in 0in 0pt" class=MsoNormal mce_style="MARGIN: 0in 0in 0pt"><SPAN style="FONT-FAMILY: '微软雅黑','sans-serif'; FONT-SIZE: 10pt" lang=ZH-CN mce_style="FONT-FAMILY: '微软雅黑','sans-serif'; FONT-SIZE: 10pt">最后，感谢大家对本博客的长期关注和支持！我们期待在事业部的其他博客上继续与各位程序员交流我们关注的技术和产品。</SPAN><SPAN style="FONT-FAMILY: '微软雅黑','sans-serif'; FONT-SIZE: 10pt" mce_style="FONT-FAMILY: '微软雅黑','sans-serif'; FONT-SIZE: 10pt"><o:p></o:p></SPAN></P>]]></content:encoded>
    </item>
    <item>
      <title>.NET 4.0新功能：Mscoree.dll + Mscoreei.dll=更少的Reboot （上）</title>
      <link>https://docs.microsoft.com/archive/blogs/silverlightshanghai/net-4-0mscoree-dll-mscoreei-dllreboot</link>
      <pubDate>Thu, 03 Sep 2009 05:24:44 GMT</pubDate>
      <dc:creator><![CDATA[SilverlightShanghai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/silverlightshanghai/2009/09/03/net-4-0mscoree-dll-mscoreei-dllreboot/</guid>
      <description><![CDATA[一次Reboot=975年  在开始本文之前先做一个小调查：有多少朋友喜欢Reboot？答案A：我喜欢，每天都要Reboot...]]></description>
      <content:encoded><![CDATA[<p><b><u>一次</u></b><b><u>Reboot=975</u></b><b><u>年</u></b><b><u></u></b></p>  <p>在开始本文之前先做一个小调查：有多少朋友喜欢Reboot？答案A：我喜欢，每天都要Reboot N次。答案B：我不喜欢，最好一个星期都不要Reboot。如果没有意外的话，相信大部分人都可以归到B那一类，毕竟很少人会愿意中断自己所做的事情，把正在编辑的文章、代码等等一一存盘，然后重新启动，等待几分钟，再重新打开文档、代码编辑的。</p>  <p>不过，很遗憾的是，新版本的.NET的安装在Vista以及以上（以后用Vista+表示）操作系统中安装通常是需要重新启动的，2003，XP或者以下则是不需要的。看到这里可能有些朋友会很奇怪：为什么XP不用重启，Vista反而要重启呢？这不是变差了吗？谈这个问题，必须要从Mscoree.dll谈起。大部分使用.NET编程的朋友可能并不熟悉mscoree.dll，但是，实际上mscoree.dll可以说是.NET/CLR中最为核心的一个部件之一，没有Mscoree，CLR根本无从加载。当你在执行一个.NET得EXE的时候，最先加载的不是CLR的DLL（mscorwks.dll），而是这个Mscoree.dll。详情可以参见我之前写过的一篇文章：<b> </b><a href="https://blog.csdn.net/ATField/archive/2007/08/19/1750890.aspx"><b>.NET</b><b>中的幕后英雄：</b><b>MSCOREE.DLL</b></a></p>  <p>因为Mscoree.dll是.NET一个核心的组成部分，可想而知，每次在安装新版本的.NET的时候，Mscoree.dll都会被更新，以加入新功能或者Bug Fix。更新的时候所面临的主要问题是：如果Mscoree.dll正在被使用，如何更新mscoree.dll？在Vista之前，也就是2003，XP，乃至之前的操作系统中，安装程序（Admin也可以）可以直接重命名mscoree.dll（这个操作即使mscoree.dll正在被使用也可以成功），然后再copy新的mscoree.dll到系统目录即可。但是，在Windows Vista+，Mscoree.dll被认为是Windows的核心组成部分之一，并且由WRP(Windows Resource Protection)所保护。如果要更新，必须得通过一种叫做CBS(Component Based Servicing)的机制加以更新（注：我对这些安装相关的技术并不太熟悉，如果细节描述上有错误欢迎指正）。这种机制虽然更加安全、健壮，但是也多了一项限制：如果Mscoree.dll正在被使用，系统必须重启才可以完成对Mscoree.dll的更新。换句话说，在Windows Vista+，安装3.5，4.0，5.0，6.0，…的.NET每一次都得要重启。比如有1亿用户安装了NET 4.0而需要重启，假定重启一次需要5分钟（包括存盘等准备工作），那么这个重启动作就浪费了所有人500000000分钟=975年！！！如果考虑到每个.NET版本的安装都要这么来一次，那么总的时间浪费可以说是天文数字！这也许有点危言耸听，但是无论如何，有一件事情是清晰的：对于像.NET这种用户群比较广泛的程序平台而言（注意我说的是.NET，不是SDK也不是VS，.NET是一个运行时、虚拟机，是最终用户所运行程序使用的），任何一个微小的细节可能都有着巨大的影响。虽然.NET用户群尚未达到这种规模，我们也不希望因为这个问题影响.NET的普及率。</p>  <p><b><u>.NET 4.0</u></b><b><u>的解决方案</u></b><b><u></u></b></p>  <p>我们的目标是希望减少重启的次数。这里谈到的重启是为了修改MSCOREE.dll而导致的重启。为了解决这个问题，我们可以先从DLL的本质入手。DLL是Windows的一种代码共享机制，这种共享是通过DLL输出函数、然后其他EXE/DLL来直接调用DLL所输出的函数来实现的。换句话说，一个DLL对于外部而言，最重要的是这个DLL的输出函数，包括其接口和功能。每次对DLL的修改，无非是接口的变化和功能的变化。接口的变化由于兼容性的要求，一般不会减少或者修改，而是增加。功能上，通常变化不会太大，一般是Bug Fix，同样，也是因为兼容性的要求。当然了，新的接口的新功能除外。那么有没有一种方法，可以自由修改MSCOREE.dll的功能和接口，而又不需要修改MSCOREE.dll的内容呢？听上去这似乎是不可能完成的任务，但是仔细思考一下，不难意识到：如果我们将MSCOREE.DLL的代码重新定位到另外一个DLL，这个DLL不受Windows约束，可以自由修改，那么问题是不是就解决了呢？答案是肯定的，这就是MSCOREEI.dll的由来。当然了，具体的细节要比这里讨论的复杂不少，这一次我就谈到这里，欢迎各位朋友参与讨论MSCOREE和MSCOREEI是如何共同作用的。因为现在这个相关项目还没有完全结束，现在暂时我还不能完全透露所有细节，在合适的时间内，我将发布本次文章的续集，并为大家公布答案。</p>]]></content:encoded>
    </item>
    <item>
      <title>.NET 4.0新功能介绍：In Process Side By Side</title>
      <link>https://docs.microsoft.com/archive/blogs/silverlightshanghai/net-4-0in-process-side-by-side</link>
      <pubDate>Tue, 25 Aug 2009 01:47:51 GMT</pubDate>
      <dc:creator><![CDATA[SilverlightShanghai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/silverlightshanghai/2009/08/25/net-4-0in-process-side-by-side/</guid>
      <description><![CDATA[我们先来看一个在Outlook上运行.NET插件的一个情景。暂时机器上面安装的是CLR...]]></description>
      <content:encoded><![CDATA[<p>我们先来看一个在Outlook上运行.NET插件的一个情景。暂时机器上面安装的是CLR v1.1，Outlook上运行了一个Addin，在v1.1上编写和测试完毕，运行良好。之后，用户在机器上面安装v2.0。因为Outlook采取的方式是总是启动最新的.NET Framework（这也是有原因的，因为Outlook希望能够运行所有的版本的.NET Addin），Outlook自动会运行CLR v2.0（包括.NET Framework v2.0,v3.0, v3.5）。因为v2.0和v1.1之间并不是100%兼容，v1.1上编写的Addin在v2.0的CLR将有可能无法正确执行。也就是说，安装了一个新版本的.NET Framework可能会导致类似Outlook这样的支持插件的应用程序上的旧插件无法正确工作！</p>  <p>如果我们来看一下类似Outlook这样基于插件（Plugin或者Addin）的程序而言，选择CLR的版本大概有这么几种方式：</p>  <p><b>1. </b><b>总是最新：</b>如上所述，总是选取最新的CLR加载存在兼容性问题。<b></b></p>  <p>2.<b>总是坚持加载某个固定的版本：比如</b><b>v1.1</b><b>或者</b><b>v2.0</b>：如果总是固定某个版本，那么基于另外的CLR的版本的Addin将很难正常运行，要么是因为基于v1.1的CLR的Addin在v2.0 CLR上因为兼容性问题磕磕碰碰，要么是基于v2.0 CLR的Addin根本无法在v1.1 CLR上运行。</p>  <p>3. <b>加载</b><b>Addin</b><b>，第一个</b><b>Addin</b><b>所加载的</b><b>CLR</b><b>将是这个进程中的唯一</b><b>CLR</b><b>（注意目前</b><b>CLR v1.X</b><b>、</b><b>v2.0</b><b>不支持在一个进程中加载多个版本的</b><b>CLR</b><b>）：</b>先不提这种方法对于加载的CLR版本有一些随机性，不管是第一个Addin是v2.0还是v1.1，最终结果和上面几种方法并无出入。</p>  <p>可见，在目前的.NET/CLR的架构下，对于这种基于插件的应用程序运行多个基于不同CLR版本的插件并没有很好的解决方案。结果是，用户选择安装新版本的.NET可能会影响已有的程序。显然这在一定程度上将会影响到人们使用新版.NET的积极性，甚至导致拒绝升级到最新版本，显然，CLR开发小组是不愿意看到这种事情发生的。解决这个问题大致有两类思路：</p>  <p>1. 保持100%兼容，vN总是可以完美运行在vM上（M&gt;N）</p>  <p>2. 承认100%兼容是不可能完成的任务，反之，允许多个不同版本的CLR共同执行</p>  <p>显然，方法一是完全不可行的，原因很简单，开发过应用程序平台的朋友们都知道，新版本的平台和旧版本的平台总是会由于各种原因不兼容。一些常见的原因有：</p>  <p>1. 旧的API被新的API所取代，旧API无法在新版本中使用。虽然常见的情况是新API和旧API并存，不过一旦并存了若干的版本之后，包袱总有被丢弃的一天。</p>  <p>2. 已有的API行为因为有若干缺陷，必须修改其行为。这种情况比较少见，通常的方法是加一个新的API，但是这种情况还是客观存在的。</p>  <p>3. 用户程序依赖于一些未定义行为，而这些未定义行为在新版本中有所改变（比如一个API的Bug，一个实现细节，或者CLR DLL的名字，等等）</p>  <p>4. 新的版本中有Bug，导致已有API行为改变</p>  <p>5. 使用某个固定的版本号</p>  <p>等等。因此，CLR采取的是第二个思路：支持多个不同版本的CLR互不干扰的共同执行，也就是Side By Side。注意，这里的Side By Side是一个很广义的词汇，它所指的是不同的CLR彼此之间互不干扰。这里的互不干扰也是有好几种层次的：</p>  <p>1. Out-Of-Process Side By Side：机器上可以安装不同版本的CLR，每个进程可以运行不同版本的CLR，互相之间互不干扰，共享机器范围的资源（如磁盘，注册表等）。目前v1.X、v2.0实现了这个功能。</p>  <p>2. In-Process Side By Side：同一个进程内可以运行多个CLR，每个CLR实例互不干扰，把对方看成本机代码。这里又分为几个层次：</p>  <p>a. 不同版本的CLR可以在同一个进程内加载，不允许同一个版本CLR加载多次</p>  <p>b. 允许加载同一个版本的CLR多次，彼此之间互不影响</p>  <p>可以看到，如果CLR可以支持在同一个进程中加载不同版本的CLR，也就是支持2.a，那么前面所提到的那个问题也就迎刃而解：v1.1的Addin运行在v1.1上，v2.0的Addin运行在v2.0上，顿时两个Addin便可以同时运行，互不干扰了！</p>  <p>幸运的是，CLR开发小组已经注意到了这个问题，并且在v4.0的CLR中实现了多个不同版本CLR的In-Process SxS，简称In-Proc SxS（也就是上面2.a所提到的内容）。下面本文将详细介绍v4.0中In-Proc SxS功能。</p>  <p><b><u>V4.0</u></b><b><u>的</u></b><b><u>In-Proc SxS</u></b><b><u>简介</u></b><b><u></u></b></p>  <p>在v4.0中CLR支持下列情况的In-Proc SxS：</p>  <p><b>1. </b><b>v2.0</b><b>和</b><b>v4.0</b><b>共存</b><b></b></p>  <p><b>2. </b><b>v1.1</b><b>和</b><b>v4.0</b><b>共存</b><b></b></p>  <p>而V1.1和V2.0则是不能够被同时加载到进程中。也就是说，进程中&lt;4.0的CLR只能存在一个实例，这样做的原因非常简单：&lt;4.0的CLR版本本身是不支持In-Proc SxS的，也就是说v1.1和v2.0一旦在同一个进程内加载是会出现各种各样的问题的。并且，我们不希望因为要支持SxS而去修改v1.1和v2.0，这样做的代价太大，同时也会把整个问题域变得更加复杂，因此最后决定不支持&lt;4.0的CLR多于一个实例。当然了，&gt;=4.0的CLR是可以多个并存的，也就是说V4.0，V5.0，v6.0，等等，都是可以和平共处在同一个进程内。原因很简单，&gt;4.0的CLR是In-Proc SxS Aware的。</p>  <p>前面提到过，总是加载最新版本的CLR这种方式是存在问题的，因为新版本不可能完全兼容旧版本，因此，保持兼容性的最佳方式是不允许“加载最新”(Bind to latest)这种方式存在，换句话说，为v4写的程序缺省应该总是在v4上运行，而不应该自动被“提升”至V5上运行。</p>  <p>因为&lt;4.0的CLR是不支持In-Proc SxS的，因此为了让这些CLR和新的V4和平共处，并且行为不变，必须满足下面几条：</p>  <p>1. 老程序的行为必须和原来保持一致，这包括已有程序的加载和已有的Hosting API</p>  <p>2. &lt;v4.0的CLR看不到&gt;=v4.0的CLR，因为它们生活在两个不同的世界中</p>  <p>3. 已有的Hosting API只允许加载一个&lt;v4.0的CLR，并且无法加载v4.0及以上的CLR</p>  <p>可以看到，已有的HostingAPI因为没有设计成支持In-Proc SxS，在v4.0的时候会面临淘汰。而在v4.0的时候，v4.0的CLR（其实严格来说是Shim，也就是mscoree.dll）必须得有一套新的API。</p>  <p><b><u>CLR</u></b><b><u>所做的修改</u></b><b><u></u></b></p>  <p>从v2.0到v4.0，从不支持In-Proc SxS到支持In-Proc SxS，CLR做出了不少的修改，这里面有不少的挑战。其中一个比较明显的修改是CLR的实现原来位于mscorwks.dll，现在被修改成了CLR.dll，同时JIT的实现原来是mscorjit，现在则是clrjit。原因非常简单，为了让已有的v1.1和v2.0的代码看不到V4的存在，避免v2.0的DLL把v4.0的CLR误认为是V2的。如果不做名字修改，已有的v2.0的代码很有可能仍然可以找到v4.0，因为内部的很多代码都是需要查找mscorwks.dll的。如果找不到这个DLL自然就找不到CLR了。</p>  <p>除此之外，CLR的代码也做出了不少的改变，比较主要的有：</p>  <p>1. 修改对全局的共享资源的使用。比如原来总是用一个固定名字的Mutex或者和进程名字相关的临时文件，现在这些代码必须得要修改了，要和该CLR的实例绑定起来（比如和首地址）。</p>  <p>2. 修改对于其他CLR的DLL的加载和查找。以前也许可以写FindModule(“mscorwks.dll”)，现在不能这么写了，而是通过其他方法来查找（比如注册表）。</p>  <p>3. 对于版本号的一些假设。原来可以直接处理任何版本的代码，现在也许需要分情况处理&lt;v4.0和&gt;=v4.0。</p>  <p>4. 对于旧的Hosting API，修改其实现使之无法加载v4.0的CLR，但是又可以和v4的CLR共处而不会出问题</p>  <p>5. 增加新的API，支持In-Proc SxS</p>  <p>6. Activation，也就是CLR的启动的Logic基本上重写，为了处理v1.1、v2.0、v4.0之间的各种不同的SxS或者非SxS的情况。</p>  <p>本文因为不是剖析v4.0中SxS实现的文章，对于CLR本身的修改也就到这里点到为止。不过，如果你的程序也有类似的问题，那么你的程序可能也要修改才可以支持SxS了。</p>  <p><b><u>Activation Policies</u></b></p>  <p>这里所说的Activation Policies，指的是加载CLR的一些规则，知道了这些规则，才可以很好的在v4.0的CLR下使用SxS。这里所需要讨论的Activation被分成三种不同的情况：</p>  <p><b>Application Activation</b></p>  <p>这里说的Application Activation就是普通的执行一个EXE程序。规则最简单来说是这样：</p>  <p>1. &gt;= 4.0的EXE总是运行在EXE所被编译的CLR版本上</p>  <p>2. &lt;4.0的EXE优先运行在被编译的CLR版本上，如果此版本不存在，则运行最新的小于V4.0版本</p>  <p>我们来看几个例子：    <table border="1" cellspacing="0" cellpadding="0"><tbody>       <tr>         <td valign="top" width="164">           <p><b>EXE</b><b>被编译的</b><b>CLR</b><b>版本号</b><b></b></p>         </td>          <td valign="top" width="132">           <p><b>机器上安装有CLR 1.1</b><b>？</b><b></b></p>         </td>          <td valign="top" width="132">           <p><b>机器上安装有CLR 2.0?</b></p>         </td>          <td valign="top" width="132">           <p><b>机器上安装有CLR 4.0?</b></p>         </td>          <td valign="top" width="132">           <p><b>结果</b><b></b></p>         </td>       </tr>        <tr>         <td valign="top" width="164">           <p><b>1.1</b></p>         </td>          <td valign="top" width="132">           <p>是</p>         </td>          <td valign="top" width="132">           <p>无所谓</p>         </td>          <td valign="top" width="132">           <p>无所谓</p>         </td>          <td valign="top" width="132">           <p>加载CLR 1.1</p>         </td>       </tr>        <tr>         <td valign="top" width="164">           <p><b>2.0</b></p>         </td>          <td valign="top" width="132">           <p>无所谓</p>         </td>          <td valign="top" width="132">           <p>是</p>         </td>          <td valign="top" width="132">           <p>无所谓</p>         </td>          <td valign="top" width="132">           <p>加载CLR 2.0</p>         </td>       </tr>        <tr>         <td valign="top" width="164">           <p><b>1.1</b></p>         </td>          <td valign="top" width="132">           <p>否</p>         </td>          <td valign="top" width="132">           <p>是</p>         </td>          <td valign="top" width="132">           <p>无所谓</p>         </td>          <td valign="top" width="132">           <p>加载CLR 2.0</p>         </td>       </tr>        <tr>         <td valign="top" width="164">           <p><b>1.1</b></p>         </td>          <td valign="top" width="132">           <p>否</p>         </td>          <td valign="top" width="132">           <p>否</p>         </td>          <td valign="top" width="132">           <p>是</p>         </td>          <td valign="top" width="132">           <p>失败</p>         </td>       </tr>        <tr>         <td valign="top" width="164">           <p><b>2.0</b></p>         </td>          <td valign="top" width="132">           <p>无所谓</p>         </td>          <td valign="top" width="132">           <p>否</p>         </td>          <td valign="top" width="132">           <p>是</p>         </td>          <td valign="top" width="132">           <p>失败</p>         </td>       </tr>     </tbody></table> </p>  <p>怎么看一个EXE被编译的CLR版本号？很简单，使用CorFlags就可以了：</p>  <pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 650px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">C:\Windows\Microsoft.NET\Framework\v2.0.50727&gt;corflags regasm.exe
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Microsoft (R) .NET Framework CorFlags Conversion Tool.  Version  4.0.20818.0
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Copyright (c) Microsoft Corporation.  All rights reserved.
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Version   : v2.0.50727
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">CLR Header: 2.5
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">PE        : PE32
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">CorFlags  : 11
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">ILONLY    : 1
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">32BIT     : 1
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Signed    : 1</pre></pre>

<p><b>COM Activation</b></p>

<p>COM Activation指的是本地代码创建一个基于托管代码的COM对象，也就是通常所说的CCW。在最新的CLR V4中，所有的托管的COM对象都必须绑定到它所被编译的CLR版本，除非：</p>

<p>1. 注册表中SupportedRuntimeVersions中有大于该版本的版本号（注意RuntimeVersion这个只是用来做一个很简单的检查，如果当前的最新CLR版本小于这个值则出错。并不代表说一定要在这个特定的CLR版本中加载）</p>

<p>2. 如果进程中已经加载了一个&lt;=2.0的CLR版本，并且该托管对象对应的CLR版本也是&lt;=2.0，那么该托管对象则会自动在该已经被加载的CLR版本中加载</p>

<p><b>V2 Hosting Activation</b></p>

<p>这里指的是V2及以前的Hosting API，包括Mscoree.dll的大部分Export函数以及支持的一系列基于COM的Hosting接口（严格来说只是类似COM）。规则很简单，保持V2的行为不变，无视V4的存在，也就是说：</p>

<p>1. CorBindToRuntime(NULL)无法加载v4及以上</p>

<p>2. CorBindToRuntime(v4.XXXXX)会失败</p>

<p>这符合之前对于V2 Hosting API的说法，只有新的API才可以支持V4的加载。</p>

<p>注意：上面几种Activation方法，都可以通过Config文件控制。如果Config文件中存在useLegacyV2RuntimeActivationPolicy并且其值为TRUE的话，恢复原来的V2的行为，也就是如果对应的CLR版本不存在，允许绑定到更新的&gt;=v4.0的版本。</p>

<p><b><u>New Hosting API</u></b><b><u>简介</u></b><b><u></u></b></p>

<p>前面提到过CLR V4有一套新的Hosting API。其实说是CLR V4，倒不如说是Shim（mscoree.dll） V4所提供的API。显然CLR不能启动它自己，因此需要Shim来代劳。已有的CorBindToRuntime这一套API基本上都被认为是“Deprecated”。新的一套API采用的是类似COM的接口方式，从一个新的API CreateInterface获得。比较重要的新接口有：</p>

<p>1. <b>ICLRMetaHost</b>：用于绑定某个版本的CLR，列举所有的CLR，等等，取代了原来的CorBindToRuntime</p>

<p>2. <b>ICLRRuntimeInfo</b>：代表某个特定版本的CLR，如V2.0.50727。可以查询其状态，目录，版本号，等等</p>

<p>3. <b>ICLRMetaHostPolicy</b>：代表绑定某个版本CLR的相关的策略，基于策略、托管程序集、版本号、配置文件等做出策略决定。注意该接口不负责加载CLR，而只是返回一个预计的CLR版本作为结果。</p>

<p>其中，ICLRMetaHost和ICLRRuntimeInfo可以说是In-Proc SxS新API的核心，因为这两个接口的定义方式决定了它们支持工作在不同多个CLR版本上，而不像已有的API总是假定当前只有一个CLR版本。下面举一个简单的例子：</p>

<pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 650px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  1: #include &lt;stdio.h&gt;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  2: #include &lt;corerror.h&gt;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  3: #include &lt;metahost.h&gt;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  4: #include &lt;windows.h&gt;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  5: #include &lt;atlbase.h&gt;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  6: 
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  7: #define IfFailReturnHr(msg) <span style="color: #0000ff">if</span> (FAILED(hr)) { wprintf(L&quot;<span style="color: #8b0000">%s (hr=0x%x)\n</span>&quot;, msg, hr); <span style="color: #0000ff">return</span> hr;}
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  8: 
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  9: HRESULT LoadAddin(LPCWSTR lpwszVersion, LPCWSTR lpwszAddinTypeName) 
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 10: {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 11:     wprintf(L&quot;<span style="color: #8b0000">Getting runtime host interface for %s\n</span>&quot;, lpwszVersion);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 12:     
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 13:     CComPtr&lt;ICLRMetaHost&gt; pMH = NULL;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 14:     HRESULT hr = CreateInterface(CLSID_CLRMetaHost, IID_PPV_ARGS(&amp;pMH));
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 15:     IfFailReturnHr(L&quot;<span style="color: #8b0000">Create Instance for ICLRMetaHost failed.</span>&quot;);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 16:     
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 17:     CComPtr&lt;ICLRRuntimeInfo&gt; pRuntime = NULL;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 18:     hr = pMH-&gt;GetRuntime(lpwszVersion, IID_PPV_ARGS(&amp;pRuntime));
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 19:     IfFailReturnHr(L&quot;<span style="color: #8b0000">GetRuntime failed.</span>&quot;);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 20:  
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 21:     DWORD cchDir = MAX_PATH;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 22:     WCHAR wszDir[MAX_PATH];
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 23:     hr = pRuntime-&gt;GetRuntimeDirectory(wszDir, &amp;cchDir);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 24:     IfFailReturnHr(L&quot;<span style="color: #8b0000">GetRuntimeDirectory failed.</span>&quot;);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 25: 
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 26:     wprintf(L&quot;<span style="color: #8b0000">Runtime directory=%s\n</span>&quot;, wszDir);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 27: 
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 28:     CComPtr&lt;ICLRRuntimeHost3&gt; pHost;   
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 29:     hr = pRuntime-&gt;GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&amp;pHost));
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 30:     IfFailReturnHr(L&quot;<span style="color: #8b0000">GetRuntime failed.</span>&quot;);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 31: 
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 32:     CComPtr&lt;IUnknown&gt; pAddin;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 33:     DWORD dwRet = 0;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 34:     hr = pHost-&gt;CreateManagedObject(lpwszAddinTypeName, IID_PPV_ARGS(&amp;pAddin));
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 35:     IfFailReturnHr(L&quot;<span style="color: #8b0000">CreateManagedObject.</span>&quot;);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 36: 
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 37:     <span style="color: #0000ff">return</span> S_OK;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 38: }
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 39: 
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 40: <span style="color: #0000ff">int</span> _cdecl wmain(<span style="color: #0000ff">int</span> argc, __in_ecount(argc) WCHAR **argv) 
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 41: {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 42:     LoadAddin(L&quot;<span style="color: #8b0000">v2.0.50727</span>&quot;, L&quot;<span style="color: #8b0000">AddinV2, AddinV2</span>&quot;);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 43:     LoadAddin(L&quot;<span style="color: #8b0000">v4.0.20506</span>&quot;, L&quot;<span style="color: #8b0000">AddinV4, AddinV4</span>&quot;);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 44: }    
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 45: </pre></pre>

<p>下面我们来简单看一下这段代码中最核心的LoadAddin函数的实现：</p>

<p>1. 首先，调用CreateInterface获得ICLRMetaHost接口</p>

<p>2. 之后，从ICLRMetaHost接口获得v4.0.20506/v2.0.50727对应的ICLRRuntimeInfo接口</p>

<p>3. 调用ICLRRuntimeInfo::GetRuntimeDirectory获得CLR所存在的目录。这里没有实际意义，只是为演示之用</p>

<p>4. 调用GetInterface获得该Runtime对应的ICLRRuntimeHost3接口并返回</p>

<p>5. 调用ICLRRuntimeHost3::CreateManagedObject来创建Addin。这个过程中对应的CLR版本会自动启动。（这里Beta1有一个小Bug：如果调用ICLRRuntimeHost::Start方法，2.0中会返回E_NOTIMPL。这个Bug在Beta2中已经被修好了）</p>

<p>大家从这里可以看到，因为ICLRRuntimeInfo以及通过调用GetInterface获得的接口总是对应着某个特定的CLR版本如v2.0或者v4.0等，这套API便支持了In-Proc SxS。新的基于插件的应用程序如果想应用In-Proc SxS，也应该使用类似方法采用这一套API来启动其插件。</p>

<p>运行该程序其结果如下：</p>

<pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 650px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Getting runtime host interface for v2.0.50727
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Runtime directory=C:\Windows\Microsoft.NET\Framework\v2.0.50727\
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Addin V2: I'm running in CLR v2.0.50727
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Getting runtime host interface for v4.0.20506
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Runtime directory=C:\Windows\Microsoft.NET\Framework\v4.0.20506\
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Addin V4: I'm running in CLR v4.0.20506</pre></pre>

<p><b><u>结束语</u></b><b><u></u></b></p>

<p>相信看到这里，大家对In-Proc SxS应该有一个清晰的认识了。CLR v4.0为了支持In-Proc SxS，支持Non-Impactful Install方面，做了不少工作，这可以说是CLR自V2版本中Generics被引入以来的最大的一个改动。这一切都是为了V4版本的CLR可以最大限度的兼容已有版本，保护用户现有的.NET应用程序不受影响，从而让用户可以放心的采用.NET平台开发程序，而不用过于担心兼容性方面的风险。</p>]]></content:encoded>
    </item>
    <item>
      <title>.NET 4.0中的新功能介绍：契约式设计 (Design By Contracts)</title>
      <link>https://docs.microsoft.com/archive/blogs/silverlightshanghai/net-4-0-design-by-contracts</link>
      <pubDate>Wed, 19 Aug 2009 21:59:09 GMT</pubDate>
      <dc:creator><![CDATA[SilverlightShanghai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/silverlightshanghai/2009/08/19/net-4-0-design-by-contracts/</guid>
      <description><![CDATA[什么是契约  我们先来看一个很简单的例子：  Void WordList.Insert(string word)...]]></description>
      <content:encoded><![CDATA[<p><b><u>什么是契约</u></b><b><u></u></b></p>  <p>我们先来看一个很简单的例子：</p>  <p>Void WordList.Insert(string word)</p>  <p>这个函数负责将word以升序插入到WordList中的单词列表中，word不可以为NULL。</p>  <p>上面这些说明文字都是用来描述此函数的行为的。当使用该函数的调用者看到这些说明文字的时候，便知道函数应该如何调用以及在不同情况下的函数行为，换言之，上面这段说明文字简单的描述了函数调用者和被调用者的一种约定，这种约定也被称之为契约(Contracts)。契约一般来讲可以分成三类，包括：</p>  <p>1. Precondition：函数调用之前需要满足何种条件：比如，参数word不可以为NULL</p>  <p>2.Postcondition：函数调用之后需要满足何种条件：比如，参数word被加入到WordList的成员m_wordList中，m_wordList元素个数+1</p>  <p>3. Invariant：函数调用之前之后总是需要满足的条件是什么：比如，m_wordList中的单词总是以升序排列</p>  <p>契约式设计这个概念是Bertrand Meyer提出的，并在Eiffel Programming Language这本书中有详细的描述，Eiffel语言本身对契约式设计支持也非常好，有兴趣的朋友可以尝试并比较一下。</p>  <p><b><u>.NET 4.0</u></b><b><u>中的</u></b><b><u>Contracts</u></b></p>  <p>在.NET 4.0中引入了对契约式设计的支持，我们来看一下，如果上面那个例子用4.0中的契约式设计功能应该如何编写：</p>  <pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  1: <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> WordList.Insert(<span style="color: #0000ff">string</span> word)
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  2: {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  3: 	CodeContract.Requires(word != <span style="color: #0000ff">null</span>);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  4: 	CodeContract.Ensures(CodeContract.OldValue&lt;<span style="color: #0000ff">int</span>&gt;(_words.Count) + 1 == _words.Count);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  5: 	CodeContract.EnsuresOnThrow&lt;ApplicationException&gt;(CodeContract.OldValue&lt;<span style="color: #0000ff">int</span>&gt;(_words.Count) == _words.Count);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  6: 	…
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  7: }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  8: </pre></pre>

<p>其中：</p>

<p>1. Contract.Requires是Precondition</p>

<p>2. Contract.Ensures是PostCondition</p>

<p>3. Contract.EnsuresOnThrow是Postcondition，和Ensures的区别是这是在Throw的情况下需要满足的Postcondition</p>

<p>可以看到，Contracts在被显式的放在代码当中，而不仅仅是说明性的文字，那这样有什么好处呢？</p>

<p>1. 提供了运行时支持：这些Contracts都是可以被运行的，并且一旦条件不被满足，会弹出类似Assert的一样的对话框报错，如下：</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/NET4.0DesignByContracts_8BBB/clip_image002_2.jpg" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/NET4.0DesignByContracts_8BBB/clip_image002_2.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image002" border="0" alt="clip_image002" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/NET4.0DesignByContracts_8BBB/clip_image002_thumb.jpg" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/NET4.0DesignByContracts_8BBB/clip_image002_thumb.jpg" width="708" height="323" /></a></p>

<p>2. 提供了静态分析支持：通过静态分析Contracts，静态分析工具可以比较容易掌握函数的各种有关信息，甚至可以作为Intellisense</p>

<p>看到这里，可能有些朋友会有一些疑问：Contracts可以做条件检查并且弹出类似Assert的对话框，这个和Assert有何区别呢？其实，Contracts和Assert的区别主要在于：</p>

<p>1. Contracts的意图更加清晰，通过不同的Requires/Ensures等等调用，代表不同类型的条件，比单纯的Assert更容易理解和进行自动分析</p>

<p>2. Contracts的位置更加统一，将3种不同条件都放在代码的开始处，而非散见在函数的开头和结尾，便于查找和分析。</p>

<p>3. 不同的开发人员、不同的小组、不同的公司、不同的库可能都会有自己的Assert，这就大大增加了自动分析的难度，也不利于开发人员编写代码。而Contracts直接被.NET 4.0支持，是统一的。</p>

<p>当然了，Contracts也和Assert有一些非常类似的地方，比如Contracts和Assert都可以运行时检查错误，也可以在随意的在代码中关闭打开。VS中支持Contracts的几种不同的典型配置：</p>

<p>1. CONTRACTS_FULL：打开所有Contracts</p>

<p>2. CONTRACTS_PRECONDITIONS：仅有Precondition</p>

<p>3. RequireAlways Only：仅有RequireAlways。RequireAlways的意思等会讲到</p>

<p>这些选项都可以通过项目的Code Contracts页面来进行修改，这个页面是通过安装Contracts工具包获得的：</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/NET4.0DesignByContracts_8BBB/clip_image004_2.jpg" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/NET4.0DesignByContracts_8BBB/clip_image004_2.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image004" border="0" alt="clip_image004" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/NET4.0DesignByContracts_8BBB/clip_image004_thumb.jpg" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/NET4.0DesignByContracts_8BBB/clip_image004_thumb.jpg" width="697" height="481" /></a></p>

<p>在这里提醒大家一下，在使用Contracts功能之前，一定要下载最新版的Contracts开发工具包：<a href="https://msdn.microsoft.com/en-us/devlabs/dd491992.aspx">https://msdn.microsoft.com/en-us/devlabs/dd491992.aspx</a></p>

<p>这个工具包提供了一系列的Contracts所需要的一些工具，文档以及VS的插件。不安装这个工具包将无法使用Contracts的功能。</p>

<p>刚才我们谈到了Requires和Ensures两种条件，这里把.NET 4.0中的最常用的几种Contracts列一下：</p>

<p>1. Requires：函数入口处必须满足的条件</p>

<p>2. Ensures：函数出口处必须满足的条件</p>

<p>3. Invariants：所有成员函数出口处都必须满足的条件</p>

<p>4. Assertions：在某一点必须满足的条件</p>

<p>5. Assumptions：在某一点必然满足的条件，用来减少不必要的警告信息</p>

<p>其中，对于Invariant需要稍作一点说明。因为Invariant是需要对每个成员函数都需要起到作用，显然如果把这个条件放在每个函数的末尾处可以起到这个效果，但是这么做显得比较笨。.NET 4.0中采取的方式是这样的：使用某个成员函数作为Invariant，上面标记ContractInvariantMethod属性，然后在这个成员函数里面用Contracts.Invariant来指定每一条Invariant条件。这样，Invariant就会对每个函数起作用了。同时，这个Invariant方法也应该标记上PureAttribute属性，表明该函数不存在副作用（不会修改对象的状态）</p>

<p><b><u>Contracts</u></b><b><u>的奥秘</u></b><b><u></u></b></p>

<p>看到这里，不知道有些朋友发现没有，不管是Ensures还是Invariant，它们的位置并不是代码应该所存在的位置。对于Ensures来讲，它是函数出口条件，那么必然在出口时候被调用，但是为什么Ensures写在前面呢？同样的，Invariant是对每个函数起作用，如果单独写一个函数作为Invariant怎么保证它会被每个函数调用到呢？其实这些都是很合理的问题。首先，Ensure和Invariant的这种写法是很合理的，原因之前也提到过了，剩下的问题是，.NET如何保证这些条件会在正确的时候被执行。其实，在编译的时候，Contracts的工具包中有一个小工具ccrewrite，这个工具负责将编译出来的二进制代码进行调整，如下：</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/NET4.0DesignByContracts_8BBB/clip_image006_2.jpg" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/NET4.0DesignByContracts_8BBB/clip_image006_2.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image006" border="0" alt="clip_image006" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/NET4.0DesignByContracts_8BBB/clip_image006_thumb.jpg" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/NET4.0DesignByContracts_8BBB/clip_image006_thumb.jpg" width="760" height="570" /></a></p>

<p>可以看到，ccrewrite负责将各种条件的位置进行调整，最终使得条件处于正确的位置。</p>

<p><b><u>接口级别的契约</u></b><b><u></u></b></p>

<p>除了在方法实现中加入契约之外，接口也可以加入契约。接口首先需要加上一个ContractClassAttribute，指向对应的ContractClass：</p>

<pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  1: [ContractClass(<span style="color: #0000ff">typeof</span>(IFooContract))]
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  2: <span style="color: #0000ff">interface</span> IFoo {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  3: 	<span style="color: #0000ff">int</span> Count { <span style="color: #0000ff">get</span>; }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  4: 	<span style="color: #0000ff">void</span> Put(<span style="color: #0000ff">int</span> <span style="color: #0000ff">value</span> );
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  5: }</pre></pre>

<p></p>

<p>而ContractClass则需声明ContractClassForAttribute，说明是IFoo的ContractClass，然后显式实现IFoo，并加入Contract：</p>

<pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  1: [ContractClassFor(<span style="color: #0000ff">typeof</span>(IFoo))]
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  2: <span style="color: #0000ff">sealed</span> <span style="color: #0000ff">class</span> IFooContract : IFoo {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  3: 	<span style="color: #0000ff">int</span> IFoo.Count {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  4: 	<span style="color: #0000ff">get</span> {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  5: 		Contract.Ensures( 0 &lt;= Contract.Result&lt;<span style="color: #0000ff">int</span>&gt;() );
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  6: 		<span style="color: #0000ff">return</span> <span style="color: #0000ff">default</span>( <span style="color: #0000ff">int</span> ); <span style="color: #008000">// dummy return</span>
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  7: 	}
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  8: }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  9: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 10: <span style="color: #0000ff">void</span> IFoo.Put(<span style="color: #0000ff">int</span> <span style="color: #0000ff">value</span>)
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 11: {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 12: 	Contract.Requires( 0 &lt;= <span style="color: #0000ff">value</span> );
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 13: }</pre></pre>

<p></p>

<p><b><u>一个完整的例子</u></b><b><u></u></b></p>

<p>现在我们来看一个完整的例子。在这个例子中WordList使用了Contract.Requires/Ensures/EnsuresOnThrow/Invariant等契约，还附送几个Bug，程序比较简单，这里就不多说了：</p>

<pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  1: <span style="color: #0000ff">using</span> System;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  2: <span style="color: #0000ff">using</span> System.Collections.Generic;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  3: <span style="color: #0000ff">using</span> System.Linq;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  4: <span style="color: #0000ff">using</span> System.Text;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  5: <span style="color: #0000ff">using</span> System.Diagnostics.Contracts;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  6: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  7: <span style="color: #0000ff">namespace</span> ContractDemo
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  8: {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">  9:     <span style="color: #0000ff">class</span> WordList
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 10:     {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 11:         <span style="color: #0000ff">private</span> List&lt;<span style="color: #0000ff">string</span>&gt; _words;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 12: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 13:         <span style="color: #0000ff">public</span> WordList(<span style="color: #0000ff">int</span> capacity)
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 14:         {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 15:             Contract.Requires(capacity &gt; 0);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 16:             _words = <span style="color: #0000ff">new</span> List&lt;<span style="color: #0000ff">string</span>&gt;(capacity);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 17:         }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 18: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 19:         <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Insert(<span style="color: #0000ff">string</span> word)
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 20:         {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 21:             Contract.Requires(word != <span style="color: #0000ff">null</span>);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 22:             Contract.Ensures(Contract.OldValue&lt;<span style="color: #0000ff">int</span>&gt;(_words.Count) + 1 == _words.Count);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 23:             Contract.EnsuresOnThrow&lt;ApplicationException&gt;(Contract.OldValue&lt;<span style="color: #0000ff">int</span>&gt;(_words.Count) == _words.Count);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 24: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 25:             <span style="color: #0000ff">int</span> i;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 26:             <span style="color: #0000ff">for</span> (i = 0; i &lt; _words.Count; ++i)
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 27:             {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 28:                 <span style="color: #0000ff">int</span> compare = <span style="color: #0000ff">string</span>.Compare(word, _words[i]);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 29:                 <span style="color: #0000ff">if</span> (compare &gt; 0)
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 30:                     <span style="color: #0000ff">break</span>;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 31:                 <span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (compare == 0)
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 32:                     <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> ApplicationException(&quot;<span style="color: #8b0000">Already exist!</span>&quot;);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 33:             }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 34: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 35:             _words.Insert(i, word);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 36:         }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 37: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 38:         [ContractInvariantMethod()]
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 39:         <span style="color: #0000ff">internal</span> <span style="color: #0000ff">void</span> Invariant()
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 40:         {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 41:             <span style="color: #008000">// No null string</span>
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 42:             Contract.Invariant(Contract.ForAll(_words, w =&gt; w != <span style="color: #0000ff">null</span>));
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 43: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 44:             <span style="color: #008000">// Make sure the words are in ascending order</span>
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 45:             Contract.Invariant(IsAscending());
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 46:         }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 47: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 48:         [Pure]
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 49:         <span style="color: #0000ff">internal</span> <span style="color: #0000ff">bool</span> IsAscending()
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 50:         {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 51:             <span style="color: #0000ff">bool</span> isAscending = <span style="color: #0000ff">true</span>;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 52:             <span style="color: #0000ff">for</span> (<span style="color: #0000ff">int</span> i = 1; i &lt; _words.Count; ++i)
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 53:             {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 54:                 <span style="color: #0000ff">if</span> (<span style="color: #0000ff">string</span>.Compare(_words[i - 1], _words[i]) &gt; 0)
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 55:                 {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 56:                     isAscending = <span style="color: #0000ff">false</span>;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 57:                     <span style="color: #0000ff">break</span>;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 58:                 }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 59:             }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 60: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 61:             <span style="color: #0000ff">return</span> isAscending;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 62:         }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 63:     }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 64: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 65:     <span style="color: #0000ff">class</span> Program
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 66:     {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 67:         <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> Main(<span style="color: #0000ff">string</span>[] args)
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 68:         {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 69:             WordList wordList = <span style="color: #0000ff">new</span> WordList(0);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 70:             wordList.Insert(&quot;<span style="color: #8b0000">Hello</span>&quot;);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 71:             wordList.Insert(&quot;<span style="color: #8b0000">World</span>&quot;);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 72:         }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 73:     }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> 74: }</pre></pre>]]></content:encoded>
    </item>
    <item>
      <title>.NET 4.0 Interop新特性ICustomQueryInterface</title>
      <link>https://docs.microsoft.com/archive/blogs/silverlightshanghai/net-4-0-interopicustomqueryinterface</link>
      <pubDate>Sun, 09 Aug 2009 22:34:00 GMT</pubDate>
      <dc:creator><![CDATA[SilverlightShanghai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/silverlightshanghai/2009/08/09/net-4-0-interopicustomqueryinterface/</guid>
      <description><![CDATA[在.NET Framework...]]></description>
      <content:encoded><![CDATA[<P>在.NET Framework v4.0发布的新功能中，在名字空间System.Runtime.InteropServices新增加了一个叫做ICustomQueryInterface的Interface, 顾名思义，这个Interface的功能就是使得用户可以自己控制QueryInterface这个COM最常用的函数的行为。在v4.0以前，所有作用于托管组件上的QI行为，都是由CLR内部的IUnkown:QueryInterface控制的，比如，如果你QI著名的IDispatch接口时，你得到的永远都是CLR提供的那个IDispatch，诸如此类的还有IMarshal/IProvideClassInfo等一些常用的Interface。如果你非常希望用自己的IDispatch实现来替换clr提供的实现，那么恭喜你，ICustomQueryInterface就是为你而生的！当然，ICustomQueryInterface所带来的，不仅仅是简单的Interface替换，它甚至可以使得Aggregate托管组件也成为现实，wow，如果你了解Aggregation的话，一定会因此而雀跃不已的。我会在另一篇文章中通过例程给大家做一个详细的介绍。</P>
<P>让我们来看看这个Interface的定义吧</P><PRE style="BORDER-RIGHT: #400040 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #400040 1px solid; PADDING-LEFT: 5px; MIN-HEIGHT: 40px; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #400040 1px solid; WIDTH: 650px; PADDING-TOP: 5px; BORDER-BOTTOM: #400040 1px solid; BACKGROUND-COLOR: #c0c0c0"><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  1: <SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">interface</SPAN> ICustomQueryInterface
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  2: {
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  3:     CustomQueryInterfaceResult GetInterface([In]<SPAN style="COLOR: #0000ff">ref</SPAN> Guid iid, <SPAN style="COLOR: #0000ff">out</SPAN> IntPtr ppv);
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  4: }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  5: </PRE></PRE>
<P>是的，就是这么简单，就一个GetInterface方法，再仔细看看它的方法参数，是不是和c++里面的QueryInterface有点神似啊。哈哈，其实你可以把它理解成QueryInterface的托管实现也无妨啊！不过它还有个小小的功能，就是如果自己不想处理这个QI，就返回NotHandled, clr看到这个返回值，就会调用自己的QI实现来帮你处理这个请求，爽吧。</P>
<P>让我们来看看有了这个Interface之后clr内部关于QI的处理流程图吧（画的是英文版，烦请大家将就一下啦，没装viso，画图超级累啊！！！！）</P>
<P><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/NET4.0InteropICustomQueryInterface_FC3/ICustomQueryInterface_2.jpg" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/NET4.0InteropICustomQueryInterface_FC3/ICustomQueryInterface_2.jpg" mce_href="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/NET4.0InteropICustomQueryInterface_FC3/ICustomQueryInterface_2.jpg"><IMG title=ICustomQueryInterface style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: inline; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=536 alt=ICustomQueryInterface src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/NET4.0InteropICustomQueryInterface_FC3/ICustomQueryInterface_thumb.jpg" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/NET4.0InteropICustomQueryInterface_FC3/ICustomQueryInterface_thumb.jpg" width=525 border=0 mce_src="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/NET4.0InteropICustomQueryInterface_FC3/ICustomQueryInterface_thumb.jpg"></A> </P>
<P>从这个图上我们可以看到，除了不能处理对IUnknown的QI请求(要求别太高嘛)，其他统统OK！</P>
<P>理论一大堆了，来实战一下。</P>
<P>看看我们的托管组件的实现</P><PRE style="BORDER-RIGHT: #400040 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #400040 1px solid; PADDING-LEFT: 5px; MIN-HEIGHT: 40px; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #400040 1px solid; WIDTH: 650px; PADDING-TOP: 5px; BORDER-BOTTOM: #400040 1px solid; BACKGROUND-COLOR: #c0c0c0"><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  1: <SPAN style="COLOR: #0000ff">using</SPAN> System;
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  2: <SPAN style="COLOR: #0000ff">using</SPAN> System.Runtime.InteropServices;
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  3: 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  4: <SPAN style="COLOR: #0000ff">namespace</SPAN> States
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  5: {    
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  6:     [Guid("<SPAN style="COLOR: #8b0000">00020400-0000-0000-C000-000000001147</SPAN>")]
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  7:     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  8:     <SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">interface</SPAN> ICQ 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  9:     { 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 10:         <SPAN style="COLOR: #0000ff">int</SPAN> func();
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 11:         <SPAN style="COLOR: #0000ff">void</SPAN> slot2();
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 12:         <SPAN style="COLOR: #0000ff">void</SPAN> slot3();
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 13:         <SPAN style="COLOR: #0000ff">void</SPAN> slot4();
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 14:     }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 15: 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 16:     [Guid("<SPAN style="COLOR: #8b0000">11120400-0000-0000-C000-000000001148</SPAN>")]
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 17:     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 18:     <SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">interface</SPAN> IA
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 19:     {
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 20:         <SPAN style="COLOR: #0000ff">int</SPAN> FuncA();
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 21:     }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 22: 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 23:     [Guid("<SPAN style="COLOR: #8b0000">22220400-0000-0000-C000-000000001149</SPAN>")]
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 24:     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 25:     <SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">interface</SPAN> IB
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 26:     {
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 27:         <SPAN style="COLOR: #0000ff">int</SPAN> FuncB();
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 28:     }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 29: 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 30: 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 31: 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 32:     [Guid("<SPAN style="COLOR: #8b0000">00020400-0000-0000-C000-000000001150</SPAN>")]
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 33:     [ClassInterface(ClassInterfaceType.None)]
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 34:     <SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">class</SPAN> StatesComServer : ICustomQueryInterface, ICQ, IA, IB
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 35:     {
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 36:           <SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">readonly</SPAN> Guid IID_IA = <SPAN style="COLOR: #0000ff">new</SPAN> Guid("<SPAN style="COLOR: #8b0000">11120400-0000-0000-C000-000000001148</SPAN>");
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 37:         
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 38:           <SPAN style="COLOR: #0000ff">public</SPAN> CustomQueryInterfaceResult GetInterface([In]<SPAN style="COLOR: #0000ff">ref</SPAN> Guid iid, <SPAN style="COLOR: #0000ff">out</SPAN> IntPtr intf)
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 39:           {
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 40:                 <SPAN style="COLOR: #0000ff">if</SPAN> (iid == WellKnownGuids.IID_IDispatch)
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 41:                 {
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 42:                     intf = Marshal.GetComInterfaceForObject(<SPAN style="COLOR: #0000ff">this</SPAN>, <SPAN style="COLOR: #0000ff">typeof</SPAN>(ICQ), CustomQueryInterfaceMode.Ignore);
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 43:                     <SPAN style="COLOR: #0000ff">return</SPAN> CustomQueryInterfaceResult.Handled;
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 44:                 }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 45: 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 46:                 <SPAN style="COLOR: #0000ff">if</SPAN> (iid == IID_IA)
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 47:                 {
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 48:                     intf = IntPtr.Zero; 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 49:                     <SPAN style="COLOR: #0000ff">return</SPAN> CustomQueryInterfaceResult.Failed;
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 50:                 }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 51: 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 52:                 intf = IntPtr.Zero;
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 53:                 <SPAN style="COLOR: #0000ff">return</SPAN> CustomQueryInterfaceResult.NotHandled;
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 54:           }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 55: 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 56:           <SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">int</SPAN> func()
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 57:           {
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 58:               Console.WriteLine("<SPAN style="COLOR: #8b0000">This is Interface ICQ, not the IDispatch!!!</SPAN>");
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 59:                <SPAN style="COLOR: #0000ff">return</SPAN> 2008;
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 60:           }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 61: 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 62:           <SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">int</SPAN> FuncA()
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 63:           {
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 64:               Console.WriteLine("<SPAN style="COLOR: #8b0000">This is Interface IA!!!</SPAN>");
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 65:               <SPAN style="COLOR: #0000ff">return</SPAN> 3008;
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 66:           }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 67: 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 68:           <SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">int</SPAN> FuncB()
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 69:           {
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 70:               Console.WriteLine("<SPAN style="COLOR: #8b0000">This is Interface IB!!!</SPAN>");
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 71:               <SPAN style="COLOR: #0000ff">return</SPAN> 4008;
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 72:           }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 73: 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 74: 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 75:         #region Empty Functions
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 76:           <SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">void</SPAN> slot2() { }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 77:           <SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">void</SPAN> slot3() { }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 78:           <SPAN style="COLOR: #0000ff">public</SPAN> <SPAN style="COLOR: #0000ff">void</SPAN> slot4() { }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 79:         #endregion
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 80:     }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 81: 
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 82: }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"> 83: </PRE></PRE>
<P>这里有两个地方需要解释一下</P>
<P>1）对于ICQ这个接口，他实际上是作为自定义的IDispatch出现的，所以理论上应该他所有的函数声明应该和IDispatch保持一致，但是个人比较偷懒，毕竟这只是一个例程，主要是将如何使用ICustomQueryInterface这个接口，所以后三个方法的用途仅仅是为了保持ICQ的虚拟函数表（一共4个函数）和IDispatch保持一致，如果真的有人在客户端调IDispatch.Invoke（函数表中的第四个函数）的话，那调用必然会被重定向到ICQ.slot4,因为两个函数的参数声明完全不一样，AccessViolationException就无法避免了。</P>
<P>2）再讲一下GetInterface的返回值，如果是CustomQueryInterfaceResult.Failed，意思是QI失败。CustomQueryInterfaceResult.NotHandled意思是让clr去处理这个请求，CustomQueryInterfaceResult.Handled是告诉clr，已经处理好了，指针值保存在intf里面，直接返回给用户就可以了。</P>
<P>再来看看我们的客户端</P><PRE style="BORDER-RIGHT: #400040 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #400040 1px solid; PADDING-LEFT: 5px; MIN-HEIGHT: 40px; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #400040 1px solid; WIDTH: 650px; PADDING-TOP: 5px; BORDER-BOTTOM: #400040 1px solid; BACKGROUND-COLOR: #c0c0c0"><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  IDispatch * pDisp = NULL;
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  printf("<SPAN style="COLOR: #8b0000">Scenario 1: QI IDispatch interface, Expected the Custom IDispatch interface\n</SPAN>");
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  hresult = pUnknown-&gt;QueryInterface(IID_IDispatch, (<SPAN style="COLOR: #0000ff">void</SPAN>**)&amp;pDisp);
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  UINT count  = 0;
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  hresult = pDisp-&gt;GetTypeInfoCount(&amp;count);
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  printf("<SPAN style="COLOR: #8b0000">Return value of GetTypeInfoCount is %d\n</SPAN>", count);  
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  IA * pA = NULL;
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  printf("<SPAN style="COLOR: #8b0000">Scenario 2: QI IA interface, Expected failed\n</SPAN>");
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  hresult = pUnknown-&gt;QueryInterface(IID_IA, (<SPAN style="COLOR: #0000ff">void</SPAN>**)&amp;pA);
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  <SPAN style="COLOR: #0000ff">if</SPAN> (FAILED(hresult))
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  {
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">    printf("<SPAN style="COLOR: #8b0000">Failed to QI IA with error code %x\n</SPAN>", count);  
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  }
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"></PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  IB * pB = NULL;
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  printf("<SPAN style="COLOR: #8b0000">Scenario 3: QI IB interface interface, Expected the IB interface\n</SPAN>");
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  hresult = pUnknown-&gt;QueryInterface(IID_IB, (<SPAN style="COLOR: #0000ff">void</SPAN>**)&amp;pB);
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  <SPAN style="COLOR: #0000ff">long</SPAN> i  = 0;
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">  hresult = pB-&gt;FuncB(&amp;i);
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0"></PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #c0c0c0">    </PRE></PRE>
<P>再来看看我们的输出结果。</P><PRE style="BORDER-RIGHT: #400040 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #400040 1px solid; PADDING-LEFT: 5px; MIN-HEIGHT: 40px; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #400040 1px solid; WIDTH: 650px; PADDING-TOP: 5px; BORDER-BOTTOM: #400040 1px solid; BACKGROUND-COLOR: #80ff80"><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #80ff80">Scenario 1: QI IDispatch interface, Expected the Custom IDispatch interface
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #80ff80">This is Interface ICQ, <SPAN style="COLOR: #0000ff">not</SPAN> the IDispatch!!!
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #80ff80">Return value of GetTypeInfoCount is 2008
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #80ff80">Scenario 2: QI iA interface, Expected failed
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #80ff80">Failed to QI IA with error code 7d8
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #80ff80">Scenario 3: QI IB interface interface, Expected the IB interface
</PRE><PRE style="FONT-SIZE: 12px; MARGIN: 0em; WIDTH: 100%; FONT-FAMILY: consolas,'Courier New',courier,monospace; BACKGROUND-COLOR: #80ff80">This is Interface IB!!!</PRE></PRE>]]></content:encoded>
    </item>
    <item>
      <title>MSDN网络广播预告：.NET 4.0中的新特性系列课程(5)：追踪CLR——使用Windows事件跟踪(ETW)观察公共语言运行时CLR(Level 300)</title>
      <link>https://docs.microsoft.com/archive/blogs/silverlightshanghai/msdn-net-4-05clr</link>
      <pubDate>Sun, 02 Aug 2009 09:59:48 GMT</pubDate>
      <dc:creator><![CDATA[SilverlightShanghai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/silverlightshanghai/2009/08/02/msdn-net-4-05clr/</guid>
      <description><![CDATA[在最新一期的.NET 4.0新特性系列课程中，我将继续给大家介绍CLR 4.0中的一些新特性。被次课程聚焦于性能，具体信息如下：   MSDN Webcast - .NET...]]></description>
      <content:encoded><![CDATA[<p>在最新一期的.NET 4.0新特性系列课程中，我将继续给大家介绍CLR 4.0中的一些新特性。被次课程聚焦于性能，具体信息如下： </p>  <p><a href="https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032422727&amp;EventCategory=4&amp;culture=zh-CN&amp;CountryCode=CN">MSDN Webcast - .NET 4.0中的新特性系列课程(5)：追踪CLR——使用Windows事件跟踪(ETW)观察公共语言运行时CLR(Level 300)</a> </p>  <p><strong>讲 师：</strong>&#160;&#160;&#160;&#160;&#160;&#160; 朱永泰&#160;&#160; <br /><strong>开始日期：</strong>&#160; 2009年8月18日 14:30中国&#160; <br /> <strong>课程简介： </strong>CLR 4.0在开发的过程中，全面支持了Windows事件跟踪。作为一个事件提供者，CLR提供了形形色色的事件，诸如垃圾回收(GC)，即时编译(Jit)等等。对CLR事件的追踪可以用来度量CLR的性能，以及帮助用户做错误诊断。本次讲座从Windows事件跟踪的基本概念入手，讲解如何追踪CLR事件，进而观察CLR的一些运作机理。 </p>  <ul></ul>]]></content:encoded>
    </item>
    <item>
      <title>CLR 4.0 安全模型</title>
      <link>https://docs.microsoft.com/archive/blogs/silverlightshanghai/clr-4-0</link>
      <pubDate>Fri, 24 Jul 2009 04:45:50 GMT</pubDate>
      <dc:creator><![CDATA[SilverlightShanghai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/silverlightshanghai/2009/07/24/clr-4-0/</guid>
      <description><![CDATA[在公共语言运行时(CLR)过往的版本中，安全模型一直是最为复杂的模块之一，由于涉及Evidence，CAS策略等机制，难以被用户使用。在Silverlight中，CLR团队提出了三层安全级别，大大简化...]]></description>
      <content:encoded><![CDATA[<p>在公共语言运行时(CLR)过往的版本中，安全模型一直是最为复杂的模块之一，由于涉及Evidence，CAS策略等机制，难以被用户使用。在Silverlight中，CLR团队提出了三层安全级别，大大简化了安全模型，得到了很多积极的反馈。所以CLR4.0对之加以改进，希望能帮助用户开发出更为安全的应用程序。</p>  <h3>三层安全级别及其运作机制</h3>  <p>CLR4.0中的安全级别，从低到高排列如下：</p>  <ul>   <li>Transparent </li>    <li>SafeCritical </li>    <li>Critical </li> </ul>  <p>其运作机制如下图所示，可以用三个箭头加以说明：</p>  <ul>   <li>Transparent的代码可以调用SafeCritical的代码 </li>    <li>SafeCritical的代码可以调用Critical的代码 </li>    <li>Transparent的代码<font color="#ff0000">不可以</font>调用Critical的代码 </li> </ul>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/CLR4.0_DD34/image_2.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/CLR4.0_DD34/image_2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/CLR4.0_DD34/image_thumb.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/CLR4.0_DD34/image_thumb.png" width="146" height="244" /></a></p>  <p>下面的代码展示了安全级别的运作机制:</p>  <pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 650px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  1: <span style="color: #0000ff">using</span> System;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  2: <span style="color: #0000ff">using</span> System.Security;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  3: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  4: <span style="color: #008000">// 这个属性使得assembly中没有Security标记的方法默认为Transparent方法</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  5: [assembly:AllowPartiallyTrustedCallers]
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  6: 
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  7: <span style="color: #0000ff">namespace</span> SecurityLevel
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  8: {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  9:     <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Program
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 10:     {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 11:         <span style="color: #008000">// 标记Foo为Critical方法。</span>
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 12:         [SecurityCritical]
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 13:         <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> Foo()
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 14:         {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 15:             Console.WriteLine(&quot;<span style="color: #8b0000">Hello Foo</span>&quot;);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 16:         }
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 17: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 18:         <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> Main()
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 19:         {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 20:             <span style="color: #008000">// 这个调用会导致以下的异常:</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 21:             <span style="color: #008000">// Unhandled Exception: System.MethodAccessException: SecurityLevel.Program.Foo()</span>
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 22:             <span style="color: #008000">// at SecurityLevel.Program.Main()</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 23:             Foo();
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 24:         }
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 25:     }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 26: }</pre></pre>

<p>Main函数由于没有任何安全属性，而且在assembly上有AllowPartiallyTrustedCallers属性，所以他的安全级别是Transparent，根据前文提及的安全机制，不能直接调用Critical函数Foo，于是命令行上显示了异常信息。</p>

<h3>应用安全级别构筑体用程序</h3>

<p>CLR提供了这样的一个机制，用户只有正确使用这些机制，才能构筑健壮的应用程序。在这里，“正确的使用”指的是合理的设置函数的安全级别，对三个安全级别设置的指导原则如下：</p>

<ul>
  <li>Critical：通常用来执行高危操作，比如对文件系统的读写。 </li>

  <li>SafeCritical：用来做安全方面的检验，或者只做限制性的操作。 </li>

  <li>Transparent：来自任何部分信任的程序代码。 </li>
</ul>

<p>举例来说，我们把三层模型应用到cookie的读写上，最底层可以有一个Critical的函数，用来在文件系统上写一个cookie文件。中间层有一个SafeCritical，用于检验cookie操作的文件是否属于特定的文件夹，就好像做一个安全检查：如果通过了，则允许操作；否则的话就拒绝之。</p>

<p>下面的例子展示了一个简化后的应用，从D盘的temp文件夹中删除文件。请参见代码中的注释理解程序。</p>

<pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 650px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  1: <span style="color: #0000ff">using</span> System;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  2: <span style="color: #0000ff">using</span> System.IO;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  3: <span style="color: #0000ff">using</span> System.Security;
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  4: 
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  5: <span style="color: #008000">// 这个属性使得assembly没有Security标记的方法默认为Transparent方法</span>
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  6: [assembly:AllowPartiallyTrustedCallers]
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  7: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  8: <span style="color: #0000ff">namespace</span> SecurityLevel
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px">  9: {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 10:     <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Program
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 11:     {
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 12:         <span style="color: #808080">/// &lt;summary&gt;</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 13:         <span style="color: #808080">/// 该函数可以删除文件系统上的任意函数。具有最高的安全级别</span>
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 14:         <span style="color: #808080">/// &lt;/summary&gt;</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 15:         <span style="color: #808080">/// &lt;param name=&quot;fileName&quot;&gt;文件名&lt;/param&gt;</span>
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 16:         [SecurityCritical]
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 17:         <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> DeleteFile(<span style="color: #0000ff">string</span> fileName)
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 18:         {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 19:             File.Delete(fileName);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 20:         }
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 21: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 22:         <span style="color: #808080">/// &lt;summary&gt;</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 23:         <span style="color: #808080">/// 该函数验证待删文件是否在d:\temp中</span>
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 24:         <span style="color: #808080">/// &lt;/summary&gt;</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 25:         <span style="color: #808080">/// &lt;param name=&quot;fileName&quot;&gt;待删文件名&lt;/param&gt;</span>
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 26:         [SecuritySafeCritical]
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 27:         <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> DeleteFileFromTemp(<span style="color: #0000ff">string</span> fileName)
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 28:         {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 29:             <span style="color: #0000ff">if</span> (fileName.StartsWith(@&quot;<span style="color: #8b0000">d:\temp</span>&quot;, StringComparison.CurrentCultureIgnoreCase)
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 30:             {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 31:                 DeleteFile(fileName);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 32:             }
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 33:             <span style="color: #0000ff">else</span>
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 34:             {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 35:                 <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> Exception(&quot;<span style="color: #8b0000">待删文件不在temp文件夹中</span>&quot;);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 36:             }
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 37:         }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 38: 
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 39:         <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> Main()
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 40:         {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 41:             <span style="color: #008000">// 该语句运行正常</span>
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 42:             DeleteFileFromTemp(@&quot;<span style="color: #8b0000">d:\temp\a.txt</span>&quot;);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 43: 
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 44:             <span style="color: #008000">// 该语句抛出异常</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 45:             DeleteFileFromTemp(@&quot;<span style="color: #8b0000">d:\a.txt</span>&quot;);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 46:         }
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 47:     }
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 48: }
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 10px"> 49: </pre></pre>

<h3>安全级别和.NET类型系统</h3>

<p>理解了安全级别的应用之后，我们来看看安全级别和.NET类型系统之间的关系：</p>

<ol>
  <li>安全级别和反射 
    <p>反射机制提供了这样三个属性来探测一个类型(Type)和方法(MethodInfo)的安全级别</p>

    <ul>
      <li>IsSecurityCritical { get; } </li>

      <li>IsSecuritySafeCritical { get; } </li>

      <li>IsSecurityTransparent { get; } </li>
    </ul>

    <p>大家可以观察到，这三个属性是只读的，因为通常境况下，编译器会写入了相关信息。</p>
  </li>

  <li>安全级别和继承 
    <p>以下两点值得注意：关于类型，子类型的安全级别必须等于或者高于父类型的安全级别；关于方法，继承的方法不能改变基类型方法的安全级别</p>
  </li>

  <li>安全级别和委托(Delegate) 
    <p>调用者不能创建一个安全级别更高的Delegate，也不能创建一个指向安全级别更高方法的Delegate。</p>
  </li>
</ol>

<h3>小结</h3>

<p>本文介绍了CLR4.0中引入的三层安全级别以及运作机制，示例了安全级别的设置原则，讲述了安全级别和类型系统的关联。</p>

<pre class="csharpcode">&#160;</pre>
<style type="text/css">


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>]]></content:encoded>
    </item>
    <item>
      <title>IL Stub Diagnostic Tool在CodePlex上发布了！</title>
      <link>https://docs.microsoft.com/archive/blogs/silverlightshanghai/il-stub-diagnostic-toolcodeplex</link>
      <pubDate>Tue, 14 Jul 2009 05:10:51 GMT</pubDate>
      <dc:creator><![CDATA[SilverlightShanghai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/silverlightshanghai/2009/07/14/il-stub-diagnostic-toolcodeplex/</guid>
      <description><![CDATA[该工具主要帮助大家诊断Interop...]]></description>
      <content:encoded><![CDATA[<p>该工具主要帮助大家诊断Interop Marshalling中间遇到的问题。它的源代码和二进制文件可以在CodePlex上下载：<a title="https://clrinterop.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=29745" href="https://clrinterop.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=29745">https://clrinterop.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=29745</a></p>  <p>本文首先介绍关于Interop Marshalling的背景，然后通过一个例子来介绍IL Stub Diagnostic工具的使用。</p>  <p><u><strong>Interop Marshalling:</strong> </u>当我们在托管代码中调用本地代码或者反过来在本地代码中调用托管代码的时候，我们就在做.Net Interop，如下图所示。当我们在托管代码和本地代码之间传递数据的时候，我们就需要Marshalling。长久以来，Marshalling一直是错误的温床。程序员需要通过设置一些列的属性来告诉CLR他们期待的marshalling逻辑，由于看不到CLR生成的具体代码（当然，在调试器里面可以看到汇编代码），所以和Marshalling相关的错误总是难于诊断。我们这次在codeplex上发布的工具就力图解决这个问题。</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/interop_2.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/interop_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="interop" border="0" alt="interop" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/interop_thumb.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/interop_thumb.png" width="577" height="150" /></a> </p>  <p><strong><u></u></strong></p>  <p><strong><u>Intermediate Language（IL） Stub</u></strong>是由CLR动态生成的用于Interop的代码。它主要做两件事情：1. 在本地代码和托管代码之间Marshal数据；2. 调用目标函数。张羿撰写的<a href="https://blogs.msdn.com/silverlightshanghai/archive/2009/06/17/clr-4-0-beta1-stub-method-redirection.aspx">CLR 4.0 Beta1新功能：Stub Method Redirection</a>一文中，也对IL Stub做了相关的介绍。</p>  <p>综合以上两点，大家多半可以猜到IL Stub Diagnostics的工作方式：该工具可以实时监测CLR生成的IL Stub，并且把stub的IL代码展示给用户。根据这些信息来诊断Marshalling过程中的错误。</p>  <p>&#160;</p>  <p><strong><u>下载文件介绍</u></strong></p>  <p>本次发行包括了两个下载文件，一个是源代码，留给有兴趣的朋友们自己研究。这里主要介绍二进制文件。解压缩之后有两个文件夹和一个文档。ILStubDiagnostic包含了本工具的可执行文件，Sample中是一个pinvoke的例子，用以展示IL Stub Diagnostic工具的功能。Tutorial是一个简单的教程，由于面向全球用户，用英语撰写，在这里会给出中文对应。</p>  <p><strong><u></u></strong></p>  <p><strong><u>运行环境介绍</u></strong></p>  <p>由于使用了CLR v4以及ETW的新功能，所以被监测的托管程序必须在安装了v4 CLR的vista（或者win2008、win7）上运行。</p>  <p>&#160;</p>  <p><strong><u>例子</u></strong></p>  <p>1) 启动IL Stub Diagnostic之后，看到如下界面：</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic1_2.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic1_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="pic1" border="0" alt="pic1" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic1_thumb.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic1_thumb.png" width="753" height="403" /></a> </p>  <p>2) 单击Start按钮之后，看到界面的右上角有一个环形动画，表示IL Stub Diagnostic正在监测中。</p>  <p>3) 运行sample文件夹下的pinvoke.exe，我们会在IL Stub列表区中得到一些IL Stub项。需要注意的是，由于pinvoke.exe调用的本地代码是32位，所以它需要运行的32位CLR上。关于32位/64位CLR的背景，可以参见我的博文：<a href="https://blog.csdn.net/mountaintaiII/archive/2009/03/19/4006138.aspx">在64位windows中运行托管程序。</a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic2_2.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic2_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="pic2" border="0" alt="pic2" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic2_thumb.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic2_thumb.png" width="605" height="429" /></a> </p>  <p>4）在IL列表区右击任何一列的标题，可以选择显示不同的IL Stub信息</p>  <p></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic3_2.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic3_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="pic3" border="0" alt="pic3" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic3_thumb.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic3_thumb.png" width="336" height="339" /></a> </p>  <p>5) 在IL列表区单击任何一个感兴趣的stub，在代码区可以看到具体内容。</p>  <p>6) 在工具栏里单击IL Code，可以把代码区最大化。</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic4_2.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic4_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="pic4" border="0" alt="pic4" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic4_thumb.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic4_thumb.png" width="596" height="421" /></a> </p>  <p>7) 初次见到IL代码的朋友可能会有些茫然，在工具下方有一组导航按钮帮你找着北。单击“Next Block”和“Previous Block”可以在看到不同的代码块，相关的注释暗示了代码的用途。</p>  <p>8) 在IL Stub代码中，我们用到了StubHelpers的API，并且用下划线标明，把鼠标移到他们上面可以看到相关的解释。</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic5_2.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic5_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="pic5" border="0" alt="pic5" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic5_thumb.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic5_thumb.png" width="591" height="82" /></a> </p>  <p></p>  <p></p>  <p>9) 有的时候，一个程序会使用多个IL Stub，界面中的过滤器区域可以帮助大家更迅速的定位自己感兴趣的Stub：</p>  <p>a. 如下图所示，设置过滤器</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic6_2.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic6_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="pic6" border="0" alt="pic6" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic6_thumb.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic6_thumb.png" width="586" height="91" /></a> </p>  <p>b. 点击工具栏上的Refresh按钮，IL Stub列表区会根据设置的过滤器更新IL Stub项。同时，过滤器列表中的文字也会被更新。</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic7_2.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic7_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="pic7" border="0" alt="pic7" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic7_thumb.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic7_thumb.png" width="590" height="43" /></a> </p>  <p>c. 如果要删除过滤器，可以右击行首，选择“Delete Filter”，并点击工具栏上的Refresh按钮。</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic8_2.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic8_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="pic8" border="0" alt="pic8" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic8_thumb.png" original-url="https://blogs.msdn.com/blogfiles/silverlightshanghai/WindowsLiveWriter/ILStubDiagnosticToolCodePlex_F15A/pic8_thumb.png" width="590" height="129" /></a> </p>  <p></p>  <p></p>  <p>&#160;</p>  <p>今天的介绍就到这里，欢迎大家给我们提供关于这个工具的使用反馈，我们会继续维护并且改进这个工具。</p>]]></content:encoded>
    </item>
    <item>
      <title>MSDN Webcast预告 - .NET 4.0中的新特性系列课程(4)：.NET 4.0 安全模型介绍(Level 200)</title>
      <link>https://docs.microsoft.com/archive/blogs/silverlightshanghai/msdn-webcast-net-4-04-net-4-0-level-200</link>
      <pubDate>Sun, 05 Jul 2009 21:10:00 GMT</pubDate>
      <dc:creator><![CDATA[SilverlightShanghai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/silverlightshanghai/2009/07/05/msdn-webcast-net-4-04-net-4-0-level-200/</guid>
      <description><![CDATA[在最新一期的.NET 4.0新特性系列课程中，我们将继续给大家介绍CLR 4.0中的一些新特性，具体信息如下：
MSDN Webcast - .NET 4.0中的新特性系列课程(4)：.NET...]]></description>
      <content:encoded><![CDATA[<P>在最新一期的.NET 4.0新特性系列课程中，我们将继续给大家介绍CLR 4.0中的一些新特性，具体信息如下：</P>
<P><SPAN id=lblEventTitle><A href="https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032420505&amp;EventCategory=4&amp;culture=zh-CN&amp;CountryCode=CN" mce_href="https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032420505&amp;EventCategory=4&amp;culture=zh-CN&amp;CountryCode=CN">MSDN Webcast - .NET 4.0中的新特性系列课程(4)：.NET 4.0 安全模型介绍(Level 200)</A></SPAN></P>
<P><B>讲 师：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </B>朱永泰&nbsp; </P>
<P><STRONG>开始日期：</STRONG>&nbsp; 2009年7月21日 14:30中国 </P>
<P><B>课程简介：</B>CLR 4在安全领域的主要工作室简化安全模型，以便让用户可以更方便的使用。本次讲座会从CLR对自身在整个安全架构的定位谈起，介绍如何提供一个安全沙箱(SandBox)，来构筑应用程序。 </P>]]></content:encoded>
    </item>
    <item>
      <title>MSDN Webcast预告：.NET 4.0中的新特性系列课程(3)：.NET 4.0 Beta1 Interop 新特性介绍 (Level 200)</title>
      <link>https://docs.microsoft.com/archive/blogs/silverlightshanghai/msdn-webcast-net-4-03-net-4-0-beta1-interop-level-20</link>
      <pubDate>Wed, 17 Jun 2009 05:32:37 GMT</pubDate>
      <dc:creator><![CDATA[SilverlightShanghai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/silverlightshanghai/2009/06/17/msdn-webcast-net-4-03-net-4-0-beta1-interop-level-20/</guid>
      <description><![CDATA[在最新一期的.NET 4.0新特性系列课程中，我们将给大家介绍Beta1中的一些新特性，具体信息如下：  .NET 4.0中的新特性系列课程(3)：.NET 4.0 Beta1 Interop...]]></description>
      <content:encoded><![CDATA[<p>在最新一期的.NET 4.0新特性系列课程中，我们将给大家介绍Beta1中的一些新特性，具体信息如下：</p>  <p><a href="https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032417433&amp;Culture=zh-CN">.NET 4.0中的新特性系列课程(3)：.NET 4.0 Beta1 Interop 新特性介绍 (Level 200)</a></p>  <p><b>讲 师：</b>张羿、朱永泰&#160; </p>  <p><b>课程简介：</b>.NET 4.0 Beta1在Interop，也就是互操作功能上有了较大的改进，主要是能够帮助开发者更自由的自定义互操作的行为，以及查找互操作中出现的错误。这次讲座我们主要介绍4个新特性：NOPIA、Customization of Com interop stubs、interop stub diagnostics, Custom QI。 </p>  <p>Update：因为时间关系，我们只介绍Stub Method Redirection（也就是Customization of COM interop stubs), Custom QI, IL stub diagnostics。其中Stub Method Redirection我们已经有一篇文章提及，详情请点击<a href="https://blog.csdn.net/ATField/archive/2009/06/17/4276177.aspx">这里</a>。</p>]]></content:encoded>
    </item>
  </channel>
</rss>