Welcome to MSDN Blogs Sign in | Join | Help

CLR & Silverlight上海研发团队的Blog

专注底层技术

Syndication

News

如果你对CLR或Silverlight有什么意见或建议,欢迎在此博客中留言。如有技术问题,欢迎访问MSDN中文论坛进行提问(请参阅链接)。 贴子以"现状"提供且没有任何担保也没有授予任何权利。如果需要转载、录用文章,必须在此留言与博客管理员书面联系取得许可,并在转载文章中注明出处。
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),来构筑应用程序。

Posted Monday, July 06, 2009 10:10 AM by SilverlightShanghai | 0 Comments

Filed under: ,

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我们已经有一篇文章提及,详情请点击这里

Posted Wednesday, June 17, 2009 6:32 PM by SilverlightShanghai | 0 Comments

Filed under:

CLR 4.0 Beta1新功能:Stub Method Redirection

.NET Framework v4.0和VisualStudio 2010 Beta1已经出来有阵子了,估计有些喜欢尝鲜的朋友已经下载试用了。这一次发布包含了大量的新功能。我们上海CLR开发团队会编写一系列的文章介绍Interop的相关新功能。我来给大家简单介绍一下Stub Method Redirection功能。这个功能是CLR上海开发团队设计、开发并测试的新功能之一,这一次我们上海CLR小组共开发了下面几个功能

1. Managed TlbImp (Rewrite)

2. Stub Method Redirection

3. IL Stub ETW Diagnostics

4. Custom QueryInterface

而在CodePlex上面:

1. 发布了TlbImp的最新版本,包括基于规则的Customization(具体可以参考:这一篇

2. 即将发布IL Stub Diagnostics Tool,可以方便大家直接观看IL Stub,内部使用IL Stub ETW Diagnostics新功能实现

除此之外,还有一些功能是由美国团队开发的:

1. NO PIA

2. IL Stub Everywhere

3. Limit Pumping

4. PreferComThanRemoting

除了NOPIA在我之前的文章已经介绍过之外,其他功能我们会陆续写文章介绍。这次我们先介绍Stub Method Redirection。在介绍这个功能之前,有必要先介绍一下相关的背景知识:

什么是IL Stub

大家都知道,在进行Interop调用的时候,CLR会对参数进行转换(也就是所谓的Marshalling),然后再调用到目标函数。这样一个参数转换和Marshalling实际上是一小段Stub(桩代码)来负责的,比如在调用MessageBox的时候,MessageBox_IL_STUB就是负责Marshalling和参数调用的Stub:

clip_image002

当然了,这里的Stub的内容只是一个简单的抽象,实际的内容会比这个复杂一些。在实际情况下,CLR在第一次执行MessageBox的时候,会动态生成MessageBox对应的IL STUB,使用内部的类似于ReflectionEmit的机制直接输出IL代码的Byte Code,然后交给JIT来编译之,比如MessageBox对应的IL Stub是这样子的:

  1: .maxstack 6 
  2: .locals (native int,int32,native int,int32,native int,native int,int32,native int,int32,int32,int32,int32)
  3: // Initialize {
  4:          /*( 0)*/ call            native int [mscorlib] System.StubHelpers.StubHelpers::GetStubContext() 
  5:          /*( 1)*/ call            void [mscorlib] System.StubHelpers.StubHelpers::DemandPermission(native int) 
  6: // } Initialize 
  7: // Marshal {
  8:          /*( 0)*/ ldc.i4.0         
  9:          /*( 1)*/ stloc.0          
 10: IL_000c: /*( 0)*/ nop             // argument {  
 11:          /*( 0)*/ ldarg.0          
 12:          /*( 1)*/ stloc.1          
 13:          /*( 0)*/ ldc.i4.1         
 14:          /*( 1)*/ stloc.0          
 15:          /*( 0)*/ nop             // } argument 
 16:          /*( 0)*/ nop             // argument {  
 17:          /*( 0)*/ ldc.i4.0         
 18:          /*( 1)*/ stloc.s         0x4 
 19:          /*( 0)*/ ldarg.1          
 20:          /*( 1)*/ brfalse         IL_0037 
 21:          /*( 0)*/ ldarg.1          
 22:          /*( 1)*/ call            instance int32 [mscorlib] System.String::get_Length() 
 23:          /*( 1)*/ ldc.i4.2         
 24:          /*( 2)*/ add              
 25:          /*( 1)*/ stloc.3          
 26:          /*( 0)*/ ldc.i4          0x105 
 27:          /*( 1)*/ ldloc.3          
 28:          /*( 2)*/ clt              
 29:          /*( 1)*/ brtrue          IL_0037 
 30:          /*( 0)*/ ldloc.3          
 31:          /*( 1)*/ localloc         
 32:          /*( 1)*/ stloc.s         0x4 
 33: IL_0037: /*( 0)*/ ldc.i4.1         
 34:          /*( 1)*/ ldarg.1          
 35:          /*( 2)*/ ldloc.s         0x4 
 36:          /*( 3)*/ call            native int [mscorlib] System.StubHelpers.CSTRMarshaler::ConvertToNative(int32,string,native int) 
 37:          /*( 1)*/ stloc.2          
 38:          /*( 0)*/ ldc.i4.2         
 39:          /*( 1)*/ stloc.0          
 40:          /*( 0)*/ nop             // } argument 
 41:          /*( 0)*/ nop             // argument {  
 42:          /*( 0)*/ ldc.i4.0         
 43:          /*( 1)*/ stloc.s         0x7 
 44:          /*( 0)*/ ldarg.2          
 45:          /*( 1)*/ brfalse         IL_006c 
 46:          /*( 0)*/ ldarg.2          
 47:          /*( 1)*/ call            instance int32 [mscorlib] System.String::get_Length() 
 48:          /*( 1)*/ ldc.i4.2         
 49:          /*( 2)*/ add              
 50:          /*( 1)*/ stloc.s         0x6 
 51:          /*( 0)*/ ldc.i4          0x105 
 52:          /*( 1)*/ ldloc.s         0x6 
 53:          /*( 2)*/ clt              
 54:          /*( 1)*/ brtrue          IL_006c 
 55:          /*( 0)*/ ldloc.s         0x6 
 56:          /*( 1)*/ localloc         
 57:          /*( 1)*/ stloc.s         0x7 
 58: IL_006c: /*( 0)*/ ldc.i4.1         
 59:          /*( 1)*/ ldarg.2          
 60:          /*( 2)*/ ldloc.s         0x7 
 61:          /*( 3)*/ call            native int [mscorlib] System.StubHelpers.CSTRMarshaler::ConvertToNative(int32,string,native int) 
 62:          /*( 1)*/ stloc.s         0x5 
 63:          /*( 0)*/ ldc.i4.3         
 64:          /*( 1)*/ stloc.0          
 65:          /*( 0)*/ nop             // } argument 
 66:          /*( 0)*/ nop             // argument {  
 67:          /*( 0)*/ ldarg.3          
 68:          /*( 1)*/ stloc.s         0x8 
 69:          /*( 0)*/ ldc.i4.4         
 70:          /*( 1)*/ stloc.0          
 71:          /*( 0)*/ nop             // } argument 
 72:          /*( 0)*/ nop             // return {  
 73:          /*( 0)*/ nop             // } return 
 74: // } Marshal 
 75: // CallMethod {
 76:          /*( 0)*/ ldloc.1          
 77:          /*( 1)*/ ldloc.2          
 78:          /*( 2)*/ ldloc.s         0x5 
 79:          /*( 3)*/ ldloc.s         0x8 
 80:          /*( 4)*/ call            native int [mscorlib] System.StubHelpers.StubHelpers::GetStubContext() 
 81:          /*( 5)*/ ldc.i4.s        0x30 
 82:          /*( 6)*/ add              
 83:          /*( 5)*/ ldind.i          
 84:          /*( 5)*/ ldind.i          
 85:          /*( 5)*/ calli           unmanaged stdcall int32(int32,native int,native int,int32) 
 86: // } CallMethod 
 87: // UnmarshalReturn {
 88:          /*( 1)*/ nop             // return {  
 89:          /*( 1)*/ stloc.s         0xa 
 90:          /*( 0)*/ ldc.i4.5         
 91:          /*( 1)*/ stloc.0          
 92:          /*( 0)*/ ldloc.s         0xa 
 93:          /*( 1)*/ stloc.s         0x9 
 94:          /*( 0)*/ ldloc.s         0x9 
 95:          /*( 1)*/ nop             // } return 
 96:          /*( 1)*/ stloc.s         0xb 
 97: // } UnmarshalReturn 
 98: // Unmarshal {
 99:          /*( 0)*/ nop             // argument {  
100:          /*( 0)*/ nop             // } argument 
101:          /*( 0)*/ nop             // argument {  
102:          /*( 0)*/ nop             // } argument 
103:          /*( 0)*/ nop             // argument {  
104:          /*( 0)*/ nop             // } argument 
105:          /*( 0)*/ nop             // argument {  
106:          /*( 0)*/ nop             // } argument 
107:          /*( 0)*/ leave           IL_00b3 
108: IL_00b3: /*( 0)*/ ldloc.s         0xb 
109:          /*( 1)*/ ret              
110: // } Unmarshal 
111: // Cleanup {
112: IL_00b6: /*( 0)*/ ldloc.0          
113:          /*( 1)*/ ldc.i4.1         
114:          /*( 2)*/ ble             IL_00ca 
115:          /*( 0)*/ ldloc.s         0x4 
116:          /*( 1)*/ brtrue          IL_00ca 
117:          /*( 0)*/ ldloc.2          
118:          /*( 1)*/ call            void [mscorlib] System.StubHelpers.CSTRMarshaler::ClearNative(native int) 
119: IL_00ca: /*( 0)*/ ldloc.0          
120:          /*( 1)*/ ldc.i4.2         
121:          /*( 2)*/ ble             IL_00df 
122:          /*( 0)*/ ldloc.s         0x7 
123:          /*( 1)*/ brtrue          IL_00df 
124:          /*( 0)*/ ldloc.s         0x5 
125:          /*( 1)*/ call            void [mscorlib] System.StubHelpers.CSTRMarshaler::ClearNative(native int) 
126: IL_00df: /*( 0)*/ endfinally       
127: // } Cleanup 
128: .try IL_000c to IL_00b3 finally handler IL_00b6 to IL_00e0
129: 

可以看到IL代码非常多,这些都是CLR内部自动生成的。因为看到这些代码有助于开发者理解内部工作原理和找到错误(一般来说是开发者本身的问题,比如MarshalAs写错了),我们将发布一个工具可以让你看到IL Stub具体内容,底层是通过调用另外一个CLR V4 Interop的新功能:IL Stub ETW Diagnostics实现的,以后有机会我会写另外一篇文章介绍。至于IL代码本身的相关内容可以参考Experts IL Assembler和Common Language Infrastructure Annotated Standard.

总的来说,一般的IL Stub总要负责下面几件事情:

1. 安全检查

2. 参数转换,包括返回值

3. 调用目标函数,检查返回值,可能会抛出异常

4. 清理临时内存

其实还有一些其他细节问题如切换GC模式等,建立Frame等等,但是这些属于CLR内部细节问题,这里不再赘述。

IL Stub的问题

IL Stub目前为止都工作的很好。其实,CLR内部本来不是所有情况下都是用IL Stub,2.0以前还存在所谓的ML Stub (Marshalling Language),专门工作在x86下,IL则是工作在x64和IA-64上,后来美国团队将之整合,现在就只有IL Stub了。看起来现在的IL Stub就足够了,不过事实上我们认为ILStub仍然存在一些问题:

1. 无法调试

    a. 目前VS暂时不支持调试IL代码

    b. 即使可以调试,绝大多数开发者根本不熟悉IL代码

    c. IL代码是动态生成,增大了调试支持实现的难度

    d. 较难通过工具直接看到(我们即将发布新工具支持看到IL Stub)

2. 不够灵活

    a. IL Stub是CLR根据内置规则生成(也就是MarshalAs那一套),开发者无法加入新的规则

    b. 开发者无法使用自己的Stub来替换ILStub

3. 组件化和维护性:CLR有大量生成IL Stub的代码,这些代码非常复杂,规则繁多,大大增加了CLR的复杂度,而且本身是由C++写成,较难维护

我们的Vision

既然IL Stub本身有这么多问题,那么我们应该如何解决这些问题呢?在开发Stub Method Redirection新功能之前,我们Team内部有一些讨论,达成的共识如下:

1. CLR只支持最简单的calli调用本地代码

2. IL Stub由编译时刻工具生成:ILStubGen.exe

   a. 工具内置数据转换规则

   b. 用户可通过插件自定义

3. 生成的IL Stub通过calli调用本地代码

4. Interop类型和Stub直接嵌入在目标程序中:NO PIA是朝这个方向的正确一步

5. CLR运行时刻加载IL Stub:Stub Method Redirection支持该功能

可以看到,按照如上的方法,CLR可以完全从生成IL stub的任务中解放出来,IL Stub的生成也从动态(运行时)转为静态(编译时),并且可以用C#编写,解决了调试、性能、组件化,维护性的众多问题。为了实现这个美好的Vision,有很多工作要做,而且这些工作显然没法在一个Release之内完成,因此我们采取的方法是迭代渐进式的。也就是说,每个Release都会添加一些功能,和这个Vision更加接近。这个Release,我们做的就是NO PIA,以及Stub Method redirection(的一部分)。

Stub Method Redirection

所谓Stub Method,也就是用户编写的编译时刻决定的Stub,可以用任意语言编写,CLR在运行时刻不会动态生成IL Stub,而是会使用用户自定义的Stub,而实现这个的秘诀就是:

ManagedToNativeComInteropStubMethodAttribute

这个Attribute有两个参数:

1. Type:Stub Method所位于的类

2. Name:Stub Method的名称。虽然我们也想实现所谓的methodof功能(类似typeof),但是让C#在4.0中替我们加上这个功能不是太现实,因此我们就先使用名字来查找,速度稍慢,但是因为相关查找只用进行一次,而且可以通过NGEN来避免查找(NGEN来负责查找然后把查找结果直接写入本地代码中),因此速度上不存在问题。

一旦在接口(非接口不可以)的某个方法上面添加上这个Attribute,CLR就知道根据这个Attribute来找Stub,而非自己生成。

用户可以通过这个功能做下面的事情:

1. 编写自己的Stub

    a. 加以优化(比如内存池之类的)

    b. 提供自定义的类型转换

2. 编写第三方工具自己生成Stub(不过一般来讲这个会是由CLR和.NET Framework提供)

任何编写的Stub Method必须满足下面这些要求:

1. 必须是静态

2. 第一个参数是接口类型

3. 其他参数和对应接口方法完全一致

4. 必须和对应接口位于同一个Assembly,这既是简化,也符合我们的Vision

5. 必须满足访问性要求:从接口的方法必须可以访问到Stub,这个和逻辑上的调用顺序是一致的

6. 不可以是generic

一旦不满足要求,CLR在执行方法的时候会抛出异常,比如:

clip_image004

这个信息是我和PM MM讨论数次之后决定的,目的是让其尽量清晰。

对于一个Stub Method来讲,通常的格式是这样子的:

  1: class FooStubClass
  2: {
  3: 	internal static void ForwardFooStub(IFoo thisObject, string arg) 
  4: 	{
  5: 		try{
  6: 			// Step 1: 	托管参数转换到非托管参数(In)
  7: 			// Step 2: 	获得调用目标函数的地址
  8: 		 	// Step 3:	通过Delegate调用目标函数
  9: 			// Step 4:	非托管参数转换到托管参数(Out) 
 10: 			// Step 5:	转换返回值
 11: 		}
 12: 		finally
 13: 		{
 14: 			// Step 6:	清理工作
 15: 		}
 16: 	}
 17: }
 18: 

下面分别解释一下:

1. 托管参数转换到非托管参数(In):一般这里调用Marshal的对应函数来进行转换,比如Marshal.StringToBSTR

2. 获得调用目标函数的地址:这个稍微复杂一点,注意因为是COM,所以需要通过虚函数表来获得:

  1:                 //
  2:                 // Get interface pointer
  3:                 //
  4:                 IntPtr pIntf = Marshal.GetComInterfaceForObject(_this, typeof(IFoo));
  5: 
  6:                 //
  7:                 // Get target
  8:                 //
  9:                 IntPtr pTarget = IntPtr.Zero;
 10: 
 11:                 unsafe
 12:                 {
 13:                     void** pVtbl = *(void***)pIntf;
 14:                     pTarget = new IntPtr(*(pVtbl + 7)); // IUnknown => 3, IDispatch => 4
 15:                 }
 16: 

比如上面的代码就获得了_this的IFoo指针,然后获取了虚函数表第八项(跳过IUnknown3个函数,IDispatch 4个函数)作为函数指针

3. 通过Delegate调用目标函数:这一步骤需要首先调用Marshal.GetDelegateForFunctionPointer获得函数指针对应的Delegate,注意Delegate的参数必须得是对应非托管的类型,比如MessageBox对应的delgate是(IntPtr, IntPtr, IntPtr, int),然后再调用delegate,传入参数

4. 非托管参数转换到托管参数(Out):转换的时候既要包括IN也要包括OUT,比如[in, out]char []这种情况,必须两种方向都要照顾到,IN在调用之前转换,而OUT则是在调用之后转换

5. 转换返回值:这个没太多好说的,和OUT比较类似

6. 清理工作:转换不要忘记清理中间生成的临时数据,比如string转换到char *需要调用Marshal.StringToCoTaskMemAnsi转换,之后调用Marshal.FreeCoTaskMem释放,释放则是在Cleanup中作

最后是一个完整的例子:

  1: Using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: using System.Runtime.InteropServices;
  6: using System.Runtime.CompilerServices;
  7: 
  8: namespace StubMethodDemo
  9: {
 10:     [ComImport]
 11:     [Guid("0741BD5F-549A-46FD-A857-0E3B23620399")]
 12:     interface IFoo
 13:     {
 14:         [MethodImplAttribute(MethodImplOptions.InternalCall)]
 15:         [ManagedToNativeComInteropStubAttribute(typeof(FooStubClass), "IFoo_Hello_Stub")]
 16:         void Hello(string name);
 17:     }
 18: 
 19:     [ComImport]
 20:     [Guid("68389CF3-212B-449D-83CB-0DD4572FEF03")]
 21:     class Foo : IFoo
 22:     {
 23:         [MethodImplAttribute(MethodImplOptions.InternalCall)]
 24:         public extern void Hello(string name);
 25:     }
 26: 
 27:     class FooStubClass
 28:     {
 29:         public delegate int IFoo_Hello_Delegate(IntPtr _this, IntPtr a);
 30: 
 31:         public void IFoo_Hello_Stub(IFoo _this, string name)
 32:         {
 33:             IntPtr nativeArg_name = IntPtr.Zero;
 34: 
 35:             try
 36:             {
 37:                 // 
 38:                 // Marshal CLR => Native
 39:                 //
 40:                 nativeArg_name = Marshal.StringToBSTR(name);
 41: 
 42:                 //
 43:                 // Get interface pointer
 44:                 //
 45:                 IntPtr pIntf = Marshal.GetComInterfaceForObject(_this, typeof(IFoo));
 46: 
 47:                 //
 48:                 // Get target
 49:                 //
 50:                 IntPtr pTarget = IntPtr.Zero;
 51: 
 52:                 unsafe
 53:                 {
 54:                     void** pVtbl = *(void***)pIntf;
 55:                     pTarget = new IntPtr(*(pVtbl + 7)); // IUnknown => 3, IDispatch => 4
 56:                 }
 57: 
 58:                 //
 59:                 // Make the call
 60:                 //
 61:                 Delegate dele = Marshal.GetDelegateForFunctionPointer(pTarget, typeof(IFoo_Hello_Delegate));
 62:                 IFoo_Hello_Delegate targetDelegate = (IFoo_Hello_Delegate)dele;
 63:                 int hr = targetDelegate(pIntf, nativeArg_name);
 64:                 if (hr < 0)
 65:                     Marshal.ThrowExceptionForHR(hr);
 66: 
 67:                 //
 68:                 // Marshal Native => CLR
 69:                 //
 70: 
 71:                 //
 72:                 // Marshal return
 73:                 //
 74:             }
 75:             finally
 76:             {
 77:                 //
 78:                 // Cleanup
 79:                 //
 80:                 if (nativeArg_name != IntPtr.Zero)
 81:                     Marshal.FreeBSTR(nativeArg_name);
 82:                 nativeArg_name = IntPtr.Zero;
 83:             }
 84:         }
 85:     }
 86: 
 87:     class Program
 88:     {
 89:         static void Main(string[] args)
 90:         {
 91:             Foo myFoo = new Foo();
 92:             myFoo.Hello("Foo!");
 93:         }
 94:     }
 95: }
 96: 

 

作者:张羿

转载请注明出处

Posted Wednesday, June 17, 2009 1:31 PM by SilverlightShanghai | 0 Comments

Filed under:

CLR 4 新特性 ------ 概览

.NET 4中发布了最新版本的公共语言运行时,简称CLR (Common Language Runtime) 。这个版本是CLR 2.0之后又一个新的版本,包含着CLR小组几年以来的辛勤工作。

CLR上海团队计划在未来的几个月内陆续介绍其中的一些特性,本文作为一个概览,先作蜻蜓点水,抛砖引玉。也欢迎大家回复本文,告诉我们你所感兴趣的话题,我们会进一步作深入的介绍。

CLR 简介

CLR作为.NET框架中最为底层的部件,扮演着运行托管代码虚拟机的角色,承担着诸如即时编译(Just In Time Compile),垃圾回收(Garbage Collect)等任务。打一个比方,如果把操作系统看做是运行二进制程序的宿主,那么CLR就是托管世界的操作系统。

netframework

图一 CLR 在.NET框架中所处的位置

CLR作为.NET框架中的一部分,总是跟着.NET发行,但是近年来.NET的发行版本从2.0一直到3.5, 但是CLR却还一直保留在2.0,如下表所示:

.NET框架版本

时间

CLR

1.0

2002.2

1.0

1.1

2003.4

1.1

2.0 (Generics)

2006.1

2.0

3.0 (WPF/WCF/WF)

2006.11

2.0

3.5 (LINQ)

2007.11

2.0

4.0 Beta

2009.5

4.0

图二 CLR 版本

大家可以看到,2.0的发行已经是三年之前的事情了,在这几年中,CLR小组的工作最后都汇集在了这次发行之中,可谓是众星云集,下面我们一一叙来。

托管与本地代码的互操作

托管代码与本地代码之间的互操作(interop)担负着.NET世界对外联系的责任。比如调用一个本地dll或者COM组件。在CLR 4中,我们作了以下工作,来提高互操作的易用性。

网络广播:http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032417433&Culture=zh-CN

1. 自定义QI(Custom QI)

当托管代码被COM调用的时候,它扮演着COM组件的角色。对于COM组件来说,IUnknown::QueryInerface(QI)是类型转化的关键。CLR4之前,为每个托管COM组件提供了一个QI实现; CLR4 允许用户自定义QI,大家可以从mscorlib中新增的interface,System.Runtime.InteropServices.ICustomQueryInterface着手了解这一新功能。

2. TlbImp源代码以及自定义工具

在托管代码中调用COM组件,需要这个COM组件用托管语言申明自己的接口,也就是Interop Assembly(IA)。在一般情况下,用户不需要自己动手撰写这些assembly,而可以使用TlbImp这个工具,根据TLB生成IA。在CLR 4的开发中,我们用托管代码把TlbImp重写了,并且把源代码公布在了codeplex上面。

发布TlbImp的源代码的好处之一,是方便使用者根据自己的需求,通过修改源代码来自拓展TlbImp的功能。我们也收集了很多客户需要自定义TlbImp的要求,并且提取了一些呼声最高的自定义请求,制作了TlbImp自定义工具,也在codeplex发行。详见http://blogs.msdn.com/silverlightshanghai/archive/2009/03/13/codeplex-tlbimp.aspx

3. 等价类型

前面提到,COM组件要为.NET所用,需要Interop Assembly。不同版本的COM组件,带来了部署上的问题。在CLR 4.0之中,我们通过等价类型的引入,就部署IA的问题,给出了更好的解决方案。

4. StubMethodReditection

自定义Stub来处理Interop中的Marshalling和目标函数调用;

5. 其他

Interop其他方面的改动,使用COM取代了原先的远程对象访问;让用户自己决定清理RCW的时机等等,会有更为详细的博文作具体介绍。

垃圾回收

垃圾回收一直是CLR中的核心模块,对托管程序运行的性能至关重要。在这个版本中,CLR引入了background GC,和原来的Concurrent GC相比,在GC进行的过程中,会更少的阻断其他进程,从而提高整个CLR的运行效率。同时,此前在sp2中引入的GC::RegisterForFullGCNotification可以让 CLR4.0可以通知用户第二代GC发生,从而使服务器有机会处理负载平衡,使得整个服务器端的处理能力不至于因为GC的发生受到太大的影响。

代码约定

在CLR4.0中,引入了代码约定,更方便用户规范代码的行为,大家可以从System.Diagnostics.Contracts这一命名空间着手,进一步了解其内容。

Corrupted state exception

CLR 4.0中,对异常处理的哲学有了一个改进:在默认情况下,try/catch语句将不能捕获诸如AccessViolationException等异常。因为这些异常的损毁(Corrupt)了机器的状态(state),即使用户捕获了它们,也无法继续执行代码,或者说,继续执行代码也会变得非常危险。

新的安全模型

用过CLR v2的安全模型的朋友们可能还会记得诸如Evidence,Policy以及Permission等概念,这些复杂的对象一起构筑了v2的安全模型的框架,CLR4.0中,安全模型被大大简化,SecurityCritical,SecurSafeCritical等一些安全级别构筑了新的安全模型的基础。

同一个进程,多个CLR

CLR4.0的出现,又添加了一个CLR的版本,尽管我们尽量保证各个不同版本之间的兼容性,但是还是可能出现一些已经开发的组件,需要特定的版本才能运行。为了确保用户过去编写的组件不会因为新的CLR版本而不能运行,CLR4.0中允许用户在一个进程中,运行不同的CLR版本,这样不同的组建就可以各取所需,运行在适合他们的CLR中了。

基本类库

基本类库,也就是mscorlib.dll,包括了诸如System.Object这样在整个类型系统中最为核心的类库。CLR4.0也包含了很多新功能:比如用于支持动态语言的System.Tuple,新的集合类型System.Collections.Generic.SortedSet,用于提高文件系统浏览性能的API,操作注册表的API,以及对内存映射文件的支持等等。

总的来说,CLR4.0相较于CLR2.0,在保证了很高的兼容性的同时,做了大量的改进工作,在之后的一系列博客中,我们团队的成员会进一步作更为具体的介绍,敬请大家期待。

Posted Saturday, June 06, 2009 11:42 PM by SilverlightShanghai | 0 Comments

Filed under: , ,

字符串marshalling进阶篇

1. 字符串Marshalling基础

在本地代码中,字符串按编码可分为ASNI字符串和Unicode字符串,按实现不同,可分为LPSTR(char*,wchar*)和BSTR。

在托管代码中,与字符串相关的有String,stringBuilder两个。

 

为了实现本地代码与托管代码中字符串的相互转换,Marshalling 引入了几个属性值。

BSTR系列

UnmanagedType.AnsiBStr

UnmanagedType.BStr [COM Interop中为默认值]

UnmanagedTYpe.TBStr

LPSTR系列:

UnmanagedType.LPStr

UnmanagedType.LPWStr

UnmanagedType.LPTStr[批女哦棵中为默认值]

2.字符串的内存操作

  • LPString的内存操作:

本地代码相关函数:CoTaskMemAlloc,CoTaskMemFree

 

  • BSTR的内存操作:

本地代码相关函数:SysAllocString,SysFreeString

3. String和StringBuilder在Marshalling中的区别

在Marshalling中,如果你要传递的字符串仅仅需要在原有的字符串中改变某个或某几个字符(in-place change),在这种情况下,你就最好在托管代码中使用StringBuilder,而不是string。

Posted Monday, June 01, 2009 1:14 PM by SilverlightShanghai | 0 Comments

Filed under:

Visual Studio 2010 + .NET 4.0Beta1发布!

Visual Studio 2010和.NET 4.0的Beta1版本终于发布了!目前Beta1还只是对MSDN的订阅者开放,到美国时间20日星期三,也就是我们的21日星期四的时候,Visual Studio 2010 / .NET 4.0 Beta1将公开对外发布。这个版本是可以安装的Setup,而非上次的虚拟机镜像,因此对于大家的机器要求会放松一些。想要观看安装图片的朋友们可以点击这篇Blog:http://www.itsmywindows.com/visual-studio-2010-first-look-installation

这一次发布距离上次的CTP发布过了大概半年的时间,这半年的时间有数量众多的新特性被开发出来,并被加入到Beta1版本之中。在接下来的几篇Blog和Webcast(具体请参看中文MSDN的相关预告),我们将主要介绍.NET 4.0 Beta1中的一些新特性,特别是我们上海CLR开发小组所负责开发的一些关于Interop的新功能,尽请期待!

Posted Tuesday, May 19, 2009 10:15 PM by SilverlightShanghai | 1 Comments

Filed under:

.NET Interop入门-P/Invoke和Reverse P/Invoke

最近在论坛上经常看到一些基本的interop的问题,给我动力写完之前的.net interop入门系列,给刚刚涉足.NET  interop的朋友们一个大体上的概念。

每每谈及.NET interop,我的脑中总是出现下面一幅图:

interop

该图代表了.net interop的四个典型场景。之前我的同事和我讨论了.NET和COM互操作的应用:

今天我主要讲一下P/Invoke和Reverse P/Invoke,和COM interop相比,P/Invoke无需注册组件,使用上更轻量,更绿色。

1. P/Invoke

P/Invoke(platform invoke)是.NET调用本地代码(native code)的一种比较轻便的方式。只需要将本地代码编写成动态链接库,然后在c#代码中,声明一个外部静态函数,并且用DllImport属性指明动态连接库的入口。举例如下:

using System;
using System.Runtime.InteropServices;

class PInvoke
{
    [DllImportAttribute("user32.dll", EntryPoint = "MessageBoxW")]
    public static extern  int MessageBoxW(
        [In]System.IntPtr hWnd,
        [In][MarshalAs(UnmanagedType.LPWStr)] string lpText,
        [In][MarshalAs(UnmanagedType.LPWStr)] string lpCaption,
        uint uType);

    public static void Main()
    {
        MessageBoxW(IntPtr.Zero, "Hello", "Interop", 0);
    }
}

稍加解释这个代码。类PInvoke中,有个MessageBoxW的函数声明,它的实现在user32.dll(系统自带)中,入口是MessageBoxW,参数的构成是根据windows API的声明而定的,我们在Codeplex上有一个工具,专门帮助大家声称一个本地代码(c++)编写的函数在托过代码(c#)中的函数声明,之前我们团队的成员也撰文介绍了这个工具的使用。

有了这个声明以后,在Main中调用MessageBox,就和调用其他托管代码一样轻松自如了。

2. Reverse P/Invoke

接着,我们来看看在本地代码中调用.NET方法。本地代码需要拿到一个.NET委托(delegate),然后把这个delegate当作一个函数指针使用,示例如下:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class Program
{
    internal delegate void DelegateMessageBox([MarshalAs(UnmanagedType.LPWStr)]string msg);

    [DllImport("Native.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern void NativeMethod(DelegateMessageBox d);

    public static void ShowMessageBox(string msg)
    {
       MessageBox.Show(msg);
    }

    public static void Main()
    {
        NativeMethod(new DelegateMessageBox(ShowMessageBox));
    }
}

这个例子中,我们希望本地代码能够调用托管函数ShowMessageBox来显示一个对话框。为了让本地代码可以调用这个函数,我们根据它的声明,定了了一个delegate,并且通过P/Invoke把这个委托传给了本地代码。本地代码可以如下调用托管代码:

#include <stdio.h>
#include <wtypes.h>

extern "C" {
    __declspec(dllexport) void NativeMethod(void (__stdcall *pShowMsgBox)(WCHAR *wChar))
    {
        (*pShowMsgBox)(L"hello reverse interop");
    }
}

注意到托管代码中的委托到了本地代码中,就是一个函数指针,本地代码可以像一个普通的函数指针一般调用托管代码。

大家可能注意到dll的声明用了extern “C”,它指明了调用规范是cdecl,在之前的托过代码的DllImport中,也相应的注明了调用约定,关于调用约定的详细介绍,可以参见我的另一篇博客

今天的介绍就到这里,大家可以把这些示例代码当作一个template,根据实际需求作相应的具体改动。

Posted Sunday, March 29, 2009 12:24 AM by SilverlightShanghai | 0 Comments

Filed under: ,

Silverlight3的7个新功能

在刚刚结束的Mix09大会上(Mix是微软面向web开发者和设计者的会议),Silverlight团队的程序经理Joe Stegman介绍了silverlight3的许多让人兴奋的新功能,摘录如下:

1. 支持更多的媒体编码格式

在Silverlight3中新增加的多媒体编码格式包括H.264,AAC,MP4。Silverlight这项技术,从出生以来,就一直把对多媒体,尤其是视频的支持,放在首要位置。这次对更多的编码格式提供支持,方便网站建设者更容易的发布、部署视频资料,只需要如下一行XML:
<MediaElement X:Name="m" source="bbb.mp4">

2. 利用GPU加速

随着显卡计算能力的加强,应用程序把越来越多的图形计算任务从CPU中拿出来交给GPU完成。然而,要利用到GPU,对程序员而言通常意味着更多的编码任务,在Silverlight3中,这个任务的复杂程度被大大简化,只需要在XAML中多加入几行XML代码,就可以轻松享受GPU的超强计算能力,贴一张GPU渲染的效果图:

mp4 

3. 透视化3D
透视化3D,简单的说,就是把2D对象放到3D空间中去。和传统的3D把一个3D空间的对象投影到2D空间中不同,透视化3D意味着更高的性能,更友好的编程接口,同时能完成我们80%的3D任务。好了,说了那么多,来看一个demo,一行XAML带来的变化:
<border.projection>
    <planeprojection rotationY="-30"/>
</border.projection>

3d-1 3d-2
以上这个例子,稍加扩展,就可以在silverlight3中,在3D空间中旋转一个控件。

4. 自定义特效
在silverlight3中,引入了shader的概念,它是一个像素粒度的操作——每当silverlight3要显示一个像素的时候,它对shader说:“我要显示这个像素了,你是否要做些处理,实现某些特效?”。我们来看看shader的强大之处:下面一个示例中,左边的图像是背景图像,右边的图像是前景图像,在silverlight3之前,我们尽管可以同时显示这两个图像,但是背景图像会被前景遮住。(当然可以设 置前景的透明度,但是这样整个前景图像的清晰度就下降了)我们在显示前景图像的时候可以应用一个shader:把所有的黑色过滤掉。这样,我们在前景上过滤掉所有黑色背景的同时,还拥有了一个清晰的火焰。

shader

5. 更多的控件支持
每一个新的silverlight版本的发布,都伴随着很多新的控件的问世。这个版本也不例外,新推出的控件有:DockPanel,Expander,Label,TreeView,ViewBox等等。在这里举一个“Save as...”(另存为)控件的例子。可能有的朋友会问,“另存为”作为一个耳熟能详的控件,为什么要等到silverlight3才提供?答案是出于安全性的考虑:silverlight为了保护用户的安全,对本地文件的读写有很大的限制。(否则的话,如果服务器端可以随意读写用户的本地文件,那么就很容易做出一个钓鱼网站了)。silverlight3中,对另存为控件的支持也有着安全性的考虑。开发人员可以创建一个SaveFileDialog实例,但是当用户选定本地文件的时候,他只能得到这个文件的stream,而不是这个文件的路径。这样的设计避免了提供一个打开任意路径的本地文件的功能,从而使silverlight运行在一个更为安全的环境中。

6. 本地消息传递(local messaging)
Silverlight是浏览器的一个插件,在同一时间可能会有多个实例。比如多个浏览器同时访问包含silverlight的网页,就会有多个silverlight的实例同时运行,本地消息传递允许这些不同的siliverlight控件实例之间互相通信。

7. 在浏览器外运行silverlight
silverlight3支持把一个silverlight页面安装到本地,用户可以像一个桌面程序一样离线使用这个程序,并且可以右键卸载这个程序。

比如下面一个浏览器中运行的国际象棋程序,用户可以在右键菜单中,把它存储为一个本地程序。

oob_install

然后,就可以像一个普通的桌面程序一样,运行这个程序了。同时,也能在这个桌面程序的右键菜单中卸载这个程序。

oob_uninstall1 

 

更多关于silverlight3的信息,可以在下面这个网站中获得

http://silverlight.net/getstarted/silverlight3/default.asp

其中包括工具的开发,第一手学习的资料(博客以及书籍),以及示例程序。

Posted Tuesday, March 24, 2009 8:40 AM by SilverlightShanghai | 3 Comments

Filed under:

CodePlex上TlbImp新版本发布:基于规则的自定义功能

大家好。距离上次我们发布在CodePlex上的新版本TlbImp已经过了快半年了。在这半年的时间内,除了主要进行.NET 4.0相关的新功能开发之外,我们上海CLR小组也没有忘记进行TlbImp相关功能的继续开发,于今年3月9日再次发布了TlbImp的一个新版本:

http://www.codeplex.com/clrinterop/Release/ProjectReleases.aspx?ReleaseId=17579

这次版本中我们引入了两个重要功能:

1. 通过规则自定义互操作程序集以及规则自定义编辑器

2. 回归测试工具

基于规则的自定义功能

我们先来看一下自定义功能。这个新版本的TlbImp允许用户通过自定义的一系列的规则来指定TlbImp如何生成最终的互操作程序集。之前有不少用户向我们提到在使用TlbImp的时候,经常需要对TlbImp生成的结果做一些修改,而且必须是自动化的修改。他们通常使用的方法是先使用ILDASM反汇编,使用Perl脚本修改反汇编代码,然后再使用ILASM重新生成互操作程序集。为了解决这个问题,我们引入了一个新功能,允许用户以非常自由的方式来定义他们最终想要看到的结果。

让我们先来看一个简单的例子:假设我们希望改变互操作程序集中的某个类型的名称。先双击打开TlbImpConfigFileEditor.exe启动自定义文件的编辑器,然后打开我们需要自定义的Type Library,这里我们选择发布版本中Samples\ChangeManagedName\ChangeManagedNameSample.tlb文件,如下:

clip_image002

左边显示的是我们需要自定义的Type Library,而右边,则是我们需要自定义的规则,这些规则可以告诉TlbImp如何修改最终生成的互操作程序集。首先,将我们需要修改的IComparable接口结点从左边拖到右边,松开鼠标,出现如下的对话框:

clip_image004

上面这个对话框是用来创建一个新的规则,规则指定TlbImp对于哪些对象应用何种动作。在这个对话框中我们需要定义这个规则所对应的动作(Action),因此需要在Action下拉框中选择ChangeManagedName,然后点击OK即可。之后编辑器状态如下(需要自己展开结点):

clip_image006

大家可以看到右边已经出现了一个新的规则叫做Change interface name,对应的Category是Type,也就是说这个规则是针对互操作程序集中的类型设置的。Condition指定了规则所需要满足的条件,选中Condition节点(或者其子节点)可以在下面的Condition Expression中看到对应的规则表达式,也就是NativeName Equal ‘ICompareable’,意思是该规则是针对任何名字叫做IComparable的类型。注意因为我们是从IComparable节点直接拖到右边,因此这些条件是编辑器自动生成的。大家如果需要也可以自己通过点击Native Equal IComparable条件来修改,或者点击<Empty>来增加新的条件。现在我们可以点击<Empty>节点,在下拉框中选择TypeKind,第二个下拉框选择Equal,第三个下拉框选择Interface,最终的结果如下:

clip_image008

注意表达式节点的组织方式是类似语法树的样子,也就是说And节点下面的互相之间是And关系,最终的结果总是可以在Condition Expression一栏看到:

( NativeName Equal 'IComparable' ) And ( TypeKind Equal 'Interface')

当编辑好了规则的时候,我们需要指定对应的具体动作的参数。因为我们需要修改对象类型的名称,双击Action下面的NewName子结点会弹出如下对话框:

clip_image010

输入我们想修改成的名字,然后点击OK。

这样一个规则就完成了:

clip_image012

修改完毕之后存盘为ChangeInterfaceName.xml,然后在命令行下面调用TlbImp,使用/config参数引用之前存盘的Config文件(黄色加亮部分:

clip_image014

之后通过ILDASM打开我们生成的结果:

clip_image016

可以看到IComparable已经被改名成了IMyInterface。

TlbImp总共支持下面几种动作(Action):

1. ChangeManagedName:修改类型、函数的名称

2. ResolveTo:将一个类型替换为另外一个类型(可以是另外一个程序集的类型)。现在已经有用户在CodePlex上面提出这个功能需求了:http://clrinterop.codeplex.com/WorkItem/View.aspx?WorkItemId=2565

3. AddAttribute:为任意类型添加任意Attribute

4. PreserveSig:为单个函数或者类型中的所有函数添加PreserveSigAttribute并相应修改函数的原型

5. ConvertTo:修改函数中的参数类型

每种对应的动作在Samples目录下面都有对应的例子,有兴趣的朋友可以参照文档自行实验。

回归测试工具

为了帮助用户在修改TlbImp代码的时候可以更容易保证自己的修改不会引起其他问题,我们引入了一个简单的回归测试工具,大家可以到这里下载:

http://clrinterop.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=17579

下载完毕之后打开Bin目录下面的TlbImpRegressionTestTool.exe,然后通过File菜单打开Testcase目录下面的testcases.xml文件:

clip_image018

可以看到所有的Testcase都被列出来了。下一步在Run菜单里面选择Settings,输入TlbImp2.exe和WinDiff.exe所在位置:

clip_image020

完毕之后,选择Run下面的Run All Testcases或者Run Selected Testcases,该工具便会调用TlbImp2.exe依次运行Testcase来检查TlbImp2的相应功能是否正确:

clip_image022

绿色为测试成功,红色为失败。如果有失败的情况,双击该行可以打开WinDiff比较TlbImp2当前生成的结果和应该生成的结果之间的区别。

最后,希望大家能够积极试用TlbImp的新功能。如果有希望看到的TlbImp的新功能,或者对目前的TlbImp有哪些觉得做的不够好的地方,都可以到下面的地址提出你的宝贵意见: http://clrinterop.codeplex.com/WorkItem/List.aspx

Posted Friday, March 13, 2009 4:31 PM by SilverlightShanghai | 5 Comments

Filed under: ,

在Silver light中进行基本的数据验证

 Silverlight 2支持基本的数据验证功能。在Silverlight 2中,当我们把数据绑定到某个UI控件的时候,该数据所具有的有效性规则也自动被绑定到了该UI控件上。比如某个数据字段被设置为整数型,当我们用非整数型数据对该字段进行更新的时候就会发生错误。我们就可以利用这个规则在UI中对输入数据进行验证。要做到这点,我们只要设置两个XAML属性,并在所定义的事件中实现我们所期望的UI行为就可以了。

比如如下的XAML代码定义了一组控件,用户通过TextBox对数据进行更新:

 

当NotifyOnValidationError和ValidatesOnExceptions这两个属性都设置为true的时候,Silverlight就会在对输入数据验证所绑定的规则发生错误的时候触发BindingValidationError事件,这样我们就会在验证发生错误时得到通知。

接下来我们要做的就是实现事件触发时的行为,也就是我们期望的UI行为。如:

在上面这段代码中,当错误发生时,控件(这里是TextBox)的背景色就会变成红色,并利用HTML页面的警告窗口给用户提示信息。而当错误被更正时,空间就会还原到默认的白色。

Posted Wednesday, February 25, 2009 1:29 PM by SilverlightShanghai | 2 Comments

Filed under:

中国首届. N E T技术大会即将在上海召开

近些年来,中国的软件技术队伍一直在快速扩大中,而国内的技术交流论坛较之欧美一直较为匮乏,大型的技术会议与活动更是屈指可数。但随着中国软件技术的蓬勃发展,已经有越来越多的软件技术工作者被邀请到更多的技术活动中来。今年2月20日、21日,中国首届.NET技术大会将于上海召开。这对中国广大使用.NET技术的开发人员以及.NET技术爱好者来说无疑是一个好消息。

 该大会由SoftCompass(祝成科技)与微软共同主办,邀请了海内外.NET领域的著名技术专家、企业界人士、以及社群精英相聚一堂,与与会者共同探讨.NET技术的应用与发展。为了能和用户近距离的交流,深度的理解用户反馈与需求,以便更好的改进下一代产品,CLR / Silverlight上海研发团队也派出了几名代表,分别就.NET的发展方向、Silverlight的具体应用及发展进行演讲。研发团队所属的上海开发工具部的部门经理徐鹏阳还将分享微软的软件研发方法与过程。

具体详情请查阅网站:http://conference.softcompass.com/net2009/ 

期待2月20日、21日与您相会在上海!

Posted Thursday, February 05, 2009 12:42 PM by SilverlightShanghai | 0 Comments

Filed under:

CLR Inside Out: Best Practices for Managed and Native Code Interoperability (托管/非托管代码互通性最佳实践)

不知道各位是否知道在每月发布的MSDN杂志上有一个CLR team负责的专栏,叫做CLR Inside Out。中文或许可以译作《CLR深入浅出》。在该专栏中,CLR team的各个研发人员深入探讨了CLR的各个方面,比如安全性、线程管理、性能管理等等。在最新的一期MSDN杂志中,CLR interop team在美国的PM发表了一篇名为《Best Practices for Managed and Native Code Interoperability》的文章,根据不同情况介绍了托管/非托管代码互通性的最佳实践。大家可以通过这里阅读该文章的网络版。

以往几期CLR Inside Out的文章可以通过这里看到。在此之前,发表的有关interop的文章还有如下几篇:

Marshaling between Managed and Unmanaged Code

Introduction to COM Interop

由于版权问题,我们无法在这里进行翻译。但是大家如果对什么话题有兴趣的话,欢迎在这里留言,给我们提出。

Posted Tuesday, January 20, 2009 12:37 PM by SilverlightShanghai | 0 Comments

Filed under:

CLR Team blog (英文)正式启动

CLR team在微软算得上一个历史悠久的团队了。作为.NET框架的核心引擎,CLR伴随.NET Framework 1.0于2002年正式发布到现在刚发布的CTP版本,经过了几次重大的改进;而CLR开发团队从成立到现在也已有十载春秋。长久以来,CLR team 一直通过各种不同渠道(如论坛、反馈网站、客户等等)关注用户对CLR运行各个方面的反馈,如性能、兼容性等方面的改进都基于用户的大量反馈,而CLR团队中的成员也纷纷通过建立博客和广大用户,尤其是开发人员,交流开发心得、发现的问题及解决方法等。用户在这些博客中的反馈都直接或间接的影响到了CLR产品在下一个版本中的重点开发。但由于所有的博客均由个人维护和管理,对CLR Team的交流始终处于间接的方式。

现在,CLR Team正式成立了网上博客(http://blogs.msdn.com/clrteam/),CLR Team以整个团队的方式来维护和管理该博客,并通过该博客与广大用户和开发人员交流,倾听各位的意见和建议,及时提供反馈。除了该博客的原创文章,博客还会转载那些CLR team中个人博客的最新文章。因此该博客将真正成为CLR相关文章的中心站点,方便用户的浏览和交流。

为了方便中国用户的阅读,我们的CLR & Silverlight上海研发团队的Blog会对CLR Team blog上的文章进行有选择的翻译。希望能对大家有所帮助,也希望能听到更多来自你们的声音!

Posted Sunday, January 04, 2009 11:13 AM by SilverlightShanghai | 1 Comments

Filed under: ,

让Silverlight开发更便捷——Silverlight工具集

CodePlex.com作为微软的开源社区,已经有越来越多的开发人员从中找到自己想要的东西(亦或代码示例,亦或实用工具)来帮助开发。同时,在微软内部,也有越来越多的开发团队选择了这种更轻量便捷的方式来发布一些有趣、实用却暂时无法放入品中的代码和工具。在前几篇博文中,我也介绍了上海开发团队负责维护的codeplex主页(http://www.codeplex.com/clrinterop),以及已经发布的一些有关interop的小工具。今天来介绍一个辅助Silverlight程序开发的codeplex主页——Silverlight工具集(Silverlight Toolkit)。它不是由上海团队负责维护的,但对Silverlight开发人员来说却非常实用。其名字也非常好记:http://www.codeplex.com/silverlight

Silverlight工具集在正常的Silverlight发布周期之外,为Silverlight的开发设计人员提供了一系列控件、组件、一些功能的改进和其它实用内容。目前最新的版本所包含的内容包括树形控件(TreeView),自动完成输入框控件(AutoCompleteBox),输入框中的数字加减控件(NumericUpDown),展开控件(Expander),隐式样式管理器(ImplicitStyleManager),新的主题(Theme),图表等等。

来看下效果图:

最后祝大家圣诞快乐~  :)

Posted Wednesday, December 24, 2008 10:55 AM by SilverlightShanghai | 1 Comments

Filed under:

.NET框架4.0中都有些什么?

前不久,在美国洛杉矶召开的Professional Developer Conference(PDC)上有一个讲座,介绍了有关.NET框架4.0中在CLR(公共语言运行时)方面的新功能。完整的视频可以在这里找到。这里做一个简单的总结:

.NET 4.0让不同组件之间工作的更好

1. 兼容性一直是个令人很头疼的问题,在.NET 4.0中,在同一个进程中,不同运行时上的组件可以同时运行,我们称之为In process Side by Side。 

2. 对于很多同时包含COM组件和托管代码的应用程序,Primary Interop Assembly (PIA) 一直程序在部署方面令人很头疼的问题。现在,.NET 4.0中加入了称为NO-PIA的新功能,使得Interop的版本类型匹配仅通过简单的属性(TypeIdentifierAttribute)和GUID就能实现,免去了繁杂的PIA部署,也减少了应用程序的部署大小。

3. P/Invoke Interop Assistant,是一个能帮助使用Interop的开发人员快速转换C语言与.NET语言方法签名的工具,在http://www.codeplex.com/clrinterop 的网站上可以免费下载到。

4. 此外,.NET 4.0也为引入动态语言与功能性语言做了相应的改进。包括一些新类型,如BigIntegers,Tuples,并对Tail recursion 的情况作了优化。

 

.NET 4.0在性能上做了进一步的提高

1. .NET 4.0提高了并行计算的线程性能。

2. .NET 4.0中加入了后台垃圾回收功能(Background GC),使得垃圾回收时发生的延迟现象明显减少。

3. 此外,对于Profiler,.NET 4.0中的Profiler提供更好的CPU采样功能,实时的堆分析和对象引用图表。

 

.NET 4.0帮助开发人员减少程序中的bug

1. .NET 4.0支持dump debugging,可以提供重现crash的信息,使开发人员对crash的情况的调试更有效。

2. .NET 4.0支持64位的混合模式调试,使得托管代码和非托管代码之间的调试更方便。

3. .NET 4.0提供Code Contracts,可以通过编程方式制定代码规则。

4. .NET 4.0对一些常见异常,如除零计算、Access Violation等,作了一些特别处理,使得这些问题在新的运行时中更难出现。

 

除了CLR相关的改进,.NET 4.0在Data,WCF,Windows Client等等方面都有很多新的功能。大家有兴趣的话可以看看.NET 4.0的海报(在线查看版/张贴版),相信会给大家一个完整的概念。 : )

Posted Friday, November 14, 2008 5:41 PM by SilverlightShanghai | 2 Comments

Filed under:

More Posts Next page »
 
© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Page view tracker