本博客停止更新公告

微软中国研发集团服务器与开发工具事业部近期调整了个别研发项目,我们希望专注于创新,并不断加深在部分产品和技术开发上的广度和深度。CLR/Silverlight小组所负责的Interop和JIT项目将近期移交给美国团队,所有工程师也将于近期转入事业部其他的大项目组,这也意味着我们从即日起挥别这个耕耘了三年的中文博客。   如果您对CLR相关的内容感兴趣,请访问美国团队的博客:http://blogs.msdn.com/clrteam/。   最后,感谢大家对本博客的长期关注和支持!我们期待在事业部的其他博客上继续与各位程序员交流我们关注的技术和产品。

1

.NET 4.0新功能:Mscoree.dll + Mscoreei.dll=更少的Reboot (上)

一次Reboot=975年 在开始本文之前先做一个小调查:有多少朋友喜欢Reboot?答案A:我喜欢,每天都要Reboot N次。答案B:我不喜欢,最好一个星期都不要Reboot。如果没有意外的话,相信大部分人都可以归到B那一类,毕竟很少人会愿意中断自己所做的事情,把正在编辑的文章、代码等等一一存盘,然后重新启动,等待几分钟,再重新打开文档、代码编辑的。 不过,很遗憾的是,新版本的.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。详情可以参见我之前写过的一篇文章: .NET中的幕后英雄:MSCOREE.DLL 因为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的普及率。 .NET 4.0的解决方案 我们的目标是希望减少重启的次数。这里谈到的重启是为了修改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是如何共同作用的。因为现在这个相关项目还没有完全结束,现在暂时我还不能完全透露所有细节,在合适的时间内,我将发布本次文章的续集,并为大家公布答案。

0

.NET 4.0新功能介绍:In Process Side By Side

我们先来看一个在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这样的支持插件的应用程序上的旧插件无法正确工作! 如果我们来看一下类似Outlook这样基于插件(Plugin或者Addin)的程序而言,选择CLR的版本大概有这么几种方式: 1. 总是最新:如上所述,总是选取最新的CLR加载存在兼容性问题。 2.总是坚持加载某个固定的版本:比如v1.1或者v2.0:如果总是固定某个版本,那么基于另外的CLR的版本的Addin将很难正常运行,要么是因为基于v1.1的CLR的Addin在v2.0 CLR上因为兼容性问题磕磕碰碰,要么是基于v2.0 CLR的Addin根本无法在v1.1 CLR上运行。 3. 加载Addin,第一个Addin所加载的CLR将是这个进程中的唯一CLR(注意目前CLR v1.X、v2.0不支持在一个进程中加载多个版本的CLR):先不提这种方法对于加载的CLR版本有一些随机性,不管是第一个Addin是v2.0还是v1.1,最终结果和上面几种方法并无出入。 可见,在目前的.NET/CLR的架构下,对于这种基于插件的应用程序运行多个基于不同CLR版本的插件并没有很好的解决方案。结果是,用户选择安装新版本的.NET可能会影响已有的程序。显然这在一定程度上将会影响到人们使用新版.NET的积极性,甚至导致拒绝升级到最新版本,显然,CLR开发小组是不愿意看到这种事情发生的。解决这个问题大致有两类思路: 1. 保持100%兼容,vN总是可以完美运行在vM上(M>N) 2. 承认100%兼容是不可能完成的任务,反之,允许多个不同版本的CLR共同执行 显然,方法一是完全不可行的,原因很简单,开发过应用程序平台的朋友们都知道,新版本的平台和旧版本的平台总是会由于各种原因不兼容。一些常见的原因有: 1. 旧的API被新的API所取代,旧API无法在新版本中使用。虽然常见的情况是新API和旧API并存,不过一旦并存了若干的版本之后,包袱总有被丢弃的一天。 2. 已有的API行为因为有若干缺陷,必须修改其行为。这种情况比较少见,通常的方法是加一个新的API,但是这种情况还是客观存在的。 3. 用户程序依赖于一些未定义行为,而这些未定义行为在新版本中有所改变(比如一个API的Bug,一个实现细节,或者CLR DLL的名字,等等) 4. 新的版本中有Bug,导致已有API行为改变 5. 使用某个固定的版本号 等等。因此,CLR采取的是第二个思路:支持多个不同版本的CLR互不干扰的共同执行,也就是Side By Side。注意,这里的Side By Side是一个很广义的词汇,它所指的是不同的CLR彼此之间互不干扰。这里的互不干扰也是有好几种层次的: 1. Out-Of-Process Side By Side:机器上可以安装不同版本的CLR,每个进程可以运行不同版本的CLR,互相之间互不干扰,共享机器范围的资源(如磁盘,注册表等)。目前v1.X、v2.0实现了这个功能。 2. In-Process Side By Side:同一个进程内可以运行多个CLR,每个CLR实例互不干扰,把对方看成本机代码。这里又分为几个层次: a. 不同版本的CLR可以在同一个进程内加载,不允许同一个版本CLR加载多次 b. 允许加载同一个版本的CLR多次,彼此之间互不影响…

3

.NET 4.0中的新功能介绍:契约式设计 (Design By Contracts)

什么是契约 我们先来看一个很简单的例子: Void WordList.Insert(string word) 这个函数负责将word以升序插入到WordList中的单词列表中,word不可以为NULL。 上面这些说明文字都是用来描述此函数的行为的。当使用该函数的调用者看到这些说明文字的时候,便知道函数应该如何调用以及在不同情况下的函数行为,换言之,上面这段说明文字简单的描述了函数调用者和被调用者的一种约定,这种约定也被称之为契约(Contracts)。契约一般来讲可以分成三类,包括: 1. Precondition:函数调用之前需要满足何种条件:比如,参数word不可以为NULL 2.Postcondition:函数调用之后需要满足何种条件:比如,参数word被加入到WordList的成员m_wordList中,m_wordList元素个数+1 3. Invariant:函数调用之前之后总是需要满足的条件是什么:比如,m_wordList中的单词总是以升序排列 契约式设计这个概念是Bertrand Meyer提出的,并在Eiffel Programming Language这本书中有详细的描述,Eiffel语言本身对契约式设计支持也非常好,有兴趣的朋友可以尝试并比较一下。 .NET 4.0中的Contracts 在.NET 4.0中引入了对契约式设计的支持,我们来看一下,如果上面那个例子用4.0中的契约式设计功能应该如何编写: 1: public void WordList.Insert(string word) 2: { 3: CodeContract.Requires(word != null); 4: CodeContract.Ensures(CodeContract.OldValue<int>(_words.Count) + 1 == _words.Count); 5: CodeContract.EnsuresOnThrow<ApplicationException>(CodeContract.OldValue<int>(_words.Count) == _words.Count); 6: … 7: } 8: 其中: 1. Contract.Requires是Precondition 2. Contract.Ensures是PostCondition 3. Contract.EnsuresOnThrow是Postcondition,和Ensures的区别是这是在Throw的情况下需要满足的Postcondition 可以看到,Contracts在被显式的放在代码当中,而不仅仅是说明性的文字,那这样有什么好处呢? 1….

0

.NET 4.0 Interop新特性ICustomQueryInterface

在.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的话,一定会因此而雀跃不已的。我会在另一篇文章中通过例程给大家做一个详细的介绍。 让我们来看看这个Interface的定义吧 1: public interface ICustomQueryInterface 2: { 3: CustomQueryInterfaceResult GetInterface([In]ref Guid iid, out IntPtr ppv); 4: } 5: 是的,就是这么简单,就一个GetInterface方法,再仔细看看它的方法参数,是不是和c++里面的QueryInterface有点神似啊。哈哈,其实你可以把它理解成QueryInterface的托管实现也无妨啊!不过它还有个小小的功能,就是如果自己不想处理这个QI,就返回NotHandled, clr看到这个返回值,就会调用自己的QI实现来帮你处理这个请求,爽吧。 让我们来看看有了这个Interface之后clr内部关于QI的处理流程图吧(画的是英文版,烦请大家将就一下啦,没装viso,画图超级累啊!!!!) 从这个图上我们可以看到,除了不能处理对IUnknown的QI请求(要求别太高嘛),其他统统OK! 理论一大堆了,来实战一下。 看看我们的托管组件的实现 1: using System; 2: using System.Runtime.InteropServices; 3: 4: namespace States 5: { 6: [Guid(“00020400-0000-0000-C000-000000001147“)] 7: [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 8: public interface ICQ 9: { 10: int func(); 11: void…

0

MSDN网络广播预告:.NET 4.0中的新特性系列课程(5):追踪CLR——使用Windows事件跟踪(ETW)观察公共语言运行时CLR(Level 300)

在最新一期的.NET 4.0新特性系列课程中,我将继续给大家介绍CLR 4.0中的一些新特性。被次课程聚焦于性能,具体信息如下: MSDN Webcast – .NET 4.0中的新特性系列课程(5):追踪CLR——使用Windows事件跟踪(ETW)观察公共语言运行时CLR(Level 300) 讲 师:       朱永泰   开始日期:  2009年8月18日 14:30中国  课程简介: CLR 4.0在开发的过程中,全面支持了Windows事件跟踪。作为一个事件提供者,CLR提供了形形色色的事件,诸如垃圾回收(GC),即时编译(Jit)等等。对CLR事件的追踪可以用来度量CLR的性能,以及帮助用户做错误诊断。本次讲座从Windows事件跟踪的基本概念入手,讲解如何追踪CLR事件,进而观察CLR的一些运作机理。

0

CLR 4.0 安全模型

在公共语言运行时(CLR)过往的版本中,安全模型一直是最为复杂的模块之一,由于涉及Evidence,CAS策略等机制,难以被用户使用。在Silverlight中,CLR团队提出了三层安全级别,大大简化了安全模型,得到了很多积极的反馈。所以CLR4.0对之加以改进,希望能帮助用户开发出更为安全的应用程序。 三层安全级别及其运作机制 CLR4.0中的安全级别,从低到高排列如下: Transparent SafeCritical Critical 其运作机制如下图所示,可以用三个箭头加以说明: Transparent的代码可以调用SafeCritical的代码 SafeCritical的代码可以调用Critical的代码 Transparent的代码不可以调用Critical的代码 下面的代码展示了安全级别的运作机制: 1: using System; 2: using System.Security; 3: 4: // 这个属性使得assembly中没有Security标记的方法默认为Transparent方法 5: [assembly:AllowPartiallyTrustedCallers] 6: 7: namespace SecurityLevel 8: { 9: public class Program 10: { 11: // 标记Foo为Critical方法。 12: [SecurityCritical] 13: static void Foo() 14: { 15: Console.WriteLine("Hello Foo"); 16: } 17: 18: static void…

0

IL Stub Diagnostic Tool在CodePlex上发布了!

该工具主要帮助大家诊断Interop Marshalling中间遇到的问题。它的源代码和二进制文件可以在CodePlex上下载:http://clrinterop.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=29745 本文首先介绍关于Interop Marshalling的背景,然后通过一个例子来介绍IL Stub Diagnostic工具的使用。 Interop Marshalling: 当我们在托管代码中调用本地代码或者反过来在本地代码中调用托管代码的时候,我们就在做.Net Interop,如下图所示。当我们在托管代码和本地代码之间传递数据的时候,我们就需要Marshalling。长久以来,Marshalling一直是错误的温床。程序员需要通过设置一些列的属性来告诉CLR他们期待的marshalling逻辑,由于看不到CLR生成的具体代码(当然,在调试器里面可以看到汇编代码),所以和Marshalling相关的错误总是难于诊断。我们这次在codeplex上发布的工具就力图解决这个问题。 Intermediate Language(IL) Stub是由CLR动态生成的用于Interop的代码。它主要做两件事情:1. 在本地代码和托管代码之间Marshal数据;2. 调用目标函数。张羿撰写的CLR 4.0 Beta1新功能:Stub Method Redirection一文中,也对IL Stub做了相关的介绍。 综合以上两点,大家多半可以猜到IL Stub Diagnostics的工作方式:该工具可以实时监测CLR生成的IL Stub,并且把stub的IL代码展示给用户。根据这些信息来诊断Marshalling过程中的错误。   下载文件介绍 本次发行包括了两个下载文件,一个是源代码,留给有兴趣的朋友们自己研究。这里主要介绍二进制文件。解压缩之后有两个文件夹和一个文档。ILStubDiagnostic包含了本工具的可执行文件,Sample中是一个pinvoke的例子,用以展示IL Stub Diagnostic工具的功能。Tutorial是一个简单的教程,由于面向全球用户,用英语撰写,在这里会给出中文对应。 运行环境介绍 由于使用了CLR v4以及ETW的新功能,所以被监测的托管程序必须在安装了v4 CLR的vista(或者win2008、win7)上运行。   例子 1) 启动IL Stub Diagnostic之后,看到如下界面: 2) 单击Start按钮之后,看到界面的右上角有一个环形动画,表示IL Stub Diagnostic正在监测中。 3) 运行sample文件夹下的pinvoke.exe,我们会在IL Stub列表区中得到一些IL Stub项。需要注意的是,由于pinvoke.exe调用的本地代码是32位,所以它需要运行的32位CLR上。关于32位/64位CLR的背景,可以参见我的博文:在64位windows中运行托管程序。 4)在IL列表区右击任何一列的标题,可以选择显示不同的IL Stub信息 5) 在IL列表区单击任何一个感兴趣的stub,在代码区可以看到具体内容。 6) 在工具栏里单击IL Code,可以把代码区最大化。 7)…

0

MSDN Webcast预告 – .NET 4.0中的新特性系列课程(4):.NET 4.0 安全模型介绍(Level 200)

在最新一期的.NET 4.0新特性系列课程中,我们将继续给大家介绍CLR 4.0中的一些新特性,具体信息如下: MSDN Webcast – .NET 4.0中的新特性系列课程(4):.NET 4.0 安全模型介绍(Level 200) 讲 师:       朱永泰  开始日期:  2009年7月21日 14:30中国 课程简介:CLR 4在安全领域的主要工作室简化安全模型,以便让用户可以更方便的使用。本次讲座会从CLR对自身在整个安全架构的定位谈起,介绍如何提供一个安全沙箱(SandBox),来构筑应用程序。

0

MSDN Webcast预告:.NET 4.0中的新特性系列课程(3):.NET 4.0 Beta1 Interop 新特性介绍 (Level 200)

在最新一期的.NET 4.0新特性系列课程中,我们将给大家介绍Beta1中的一些新特性,具体信息如下: .NET 4.0中的新特性系列课程(3):.NET 4.0 Beta1 Interop 新特性介绍 (Level 200) 讲 师:张羿、朱永泰  课程简介:.NET 4.0 Beta1在Interop,也就是互操作功能上有了较大的改进,主要是能够帮助开发者更自由的自定义互操作的行为,以及查找互操作中出现的错误。这次讲座我们主要介绍4个新特性:NOPIA、Customization of Com interop stubs、interop stub diagnostics, Custom QI。 Update:因为时间关系,我们只介绍Stub Method Redirection(也就是Customization of COM interop stubs), Custom QI, IL stub diagnostics。其中Stub Method Redirection我们已经有一篇文章提及,详情请点击这里。

0