Welcome to MSDN Blogs Sign in | Join | Help

CLR & Silverlight上海研发团队的Blog

专注底层技术

Syndication

News

如果你对CLR或Silverlight有什么意见或建议,欢迎通过导航条中的EMAIL给我们留言。有技术问题欢迎访问MSDN中文论坛进行提问(请参阅链接)。 贴子以"现状"提供且没有任何担保也没有授予任何权利。如果需要转载、录用文章,必须点击Email与博客管理员书面联系取得许可。
在COM应用中使用.NET组件

上一博中,我们用Visual Studio.NET组件(托管组件)变成了COM服务器。本博继续这个话题,看看如何使用.NET工具包来完成相应的功能。

首先我们来看看今天的主题和CLR Interop的关系,在我们组里,interop这个术语包含了四个范畴,即P/Invoke, Reverse P/Invoke, COM InteropReverse COM Interop。前二个概念通过动态连接库(DLL)native世界和.NET世界中实现互通性;后两个概念顾名思义,就是和COM打交道了。其中,COM interop是在.NET应用中使用COM组件;Reverse COM Interop指的是在COM应用中使用.NET组件。概念有些绕口令,看官先别急着抛转,看看下图。

可能有人会问, COM技术已经历史悠久了,.NET程序员为什么需要和它打交道呢?问题的答案就在于组件一词。举个例子,若干年前一个牛人写了个程序,扩展性极佳,他用了COM把插件的接口定义的明明白白,而我们想用.NET来做这个插件。。。

COM写一个.NET组件,可以参照以下三部曲

1.       定义.NET接口,撰写.NET class

2.       部署.NET组件

3.       撰写COM客户端

第一步骤对经常从事.NET的开发朋友来说非常熟悉,这里给出例子,不再赘述。

csc /target:library a.cs

第二,要部署.NET组件,这里包括两个方面:

regasm a.dll /tlb

1.       把类型库(type library)导出。对于COM应用来说,它只懂得类型库,是为COM组件遵循的二进制标准/tlb选项告诉regasm,导出类型库。我们可以用oleview察看tlb的内容,如下图所示,此前定义的.NET接口和类都在其中。

 

2.       把步骤2中生成的dll放到注册表中。COM并不懂得诸如GAC的概念,而是通过注册表来查询HKEY_CLASSES_ROOT\CLS_ID\00000000-0000-0000-FFFF-000000000004,观察这个注册表项,InprocServer32中把COM的动态链接库指向了mscoree.dll,这就是传说中的垫片(shim),它会负责加载公共语言运行时,并找到真正的.NET组件----a.dll

 

有了以上两步,我们就可以在COM应用中使用.NET组件了。如何撰写COM组件超出了本文的范畴,有兴趣的读者可以参考代码中的注释。

cl client.cs

// client.cs

#define _WIN32_COM

#include <stdio.h>

#include <wtypes.h>

 

#import "a.tlb" no_namespace named_guids raw_interfaces_only

// a.tlb是第二步中导出的

int main()

{

      IUnknown *pUnk = NULL;

      IA *pIA = NULL;

      HRESULT hresult;

 

      // 0. 初始化COM组件

      hresult = CoInitializeEx(NULL, COINIT_MULTITHREADED);

      if (FAILED(hresult))

      {

            printf("ERROR: cannot initialze COM: 0x%x\n", hresult);

            return -1;

      }

 

      // 1. 获取IUnknown接口

      hresult = CoCreateInstance(CLSID_A, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&pUnk);

      if (FAILED(hresult))

      {

            printf("ERROR: cannot Get the IUnkown interface: 0x%x\n", hresult);

            return -1;

      }

 

      // 2. 获得IA接口

      hresult = pUnk->QueryInterface(IID_IA, (void **)&pIA);

      if (FAILED(hresult))

      {

            printf("ERROR: cannot Convert to IDispatch interface: 0x%x\n", hresult);

            pUnk->Release();

            return -1;

      }

     

 

      pUnk->Release();

 

      // 3. 调用.NET组件

      hresult = pIA->Hello();

      if (FAILED(hresult))

      {

            printf("ERROR: Invoke failed: 0x%x\n", hresult);

      }

 

      // 4. 清理

      pIA->Release();

      CoUninitialize();

      return 0;

}

 

                                                                                                                                                    By com.microsoft.stbc.devdiv.ndp.interop.dev/mountaintai二世

Posted Wednesday, July 23, 2008 11:51 PM by SilverlightShanghai | 1 Comments

Filed under:

使用IDispatch::Invoke函数在C++中调用C#实现的托管类库方法
 

CLR Interop简而言之是让非托管代码与托管代码之间可以相互调用的技术。这项技术可以使开发人员重用已有的托管或非托管组建,并根据自己的需要,权衡托管代码的简易性与非托管代码的灵活性,选择适合自己实际情况的编程语言,而不用过多考虑重用的组件是用哪种语言开发的。Interop中文的意思是互通性,既然是互通,代码的调用就有两种不同的方向。本文所要讲述的是使用COM Interop技术在非托管代码方如何调用托管代码。

1. 创建托管服务器

首先让我们在Visual Studio 2008创建一个C#的Class Library(类库)项目,取名为MyManagedServer,在该项目中,我们要声明并实现一个接口。

接口声明代码如下:

为了说明简单,该接口中只有一个方法,用于打印一些信息。其中的ComVisible属性至关重要,当它的值为true时,该接口才对COM可见。

  1. using System;   
  2. using System.Runtime.InteropServices;   
  3.   
  4. namespace MyManagedServer   
  5. {   
  6.     [ComVisible(true),   
  7.      Guid("79EDDA1C-F243-47C5-8954-5DEF01FA3D44"),   
  8.      InterfaceType(ComInterfaceType.InterfaceIsDual)]        
  9.     public interface IManagedFooClass   
  10.     {   
  11.         [PreserveSig, DispId(1)]   
  12.         void PrintFoo();   
  13.     }   
  14. }  

接下来是实现该接口的类:

  1. using System;   
  2. using System.Runtime.InteropServices;   
  3.   
  4. namespace MyManagedServer   
  5. {   
  6.     [ComVisible(true),   
  7.      ClassInterface(ClassInterfaceType.AutoDual),   
  8.      ProgId("MyManagedServer.ManagedFooClass")   
  9.     ]   
  10.     public class CustomCOMClient : 
  11.                              IManagedFooClass, 
  12.                              IManagedBarClass   
  13.     {   
  14.         public CustomCOMClient()   
  15.         {   
  16.         }  
  17.           
  18.         #region IManagedFooClass Members   
  19.   
  20.         [DispId(1)]   
  21.         public void PrintFoo()   
  22.         {   
  23.             Console.WriteLine("in MyManagedServer: CustomCOMClient.PrintFoo()");   
  24.         }  
  25.         #endregion   
  26.     }   
  27. }   

这里我们给这个类的ProgId属性赋一个值。等会儿在注册组件的时候,注册表中将会增加一个键值,将ProgId和runtime为我们自动生成的CLSID关联起来。

2. 为COM Interop注册托管服务组件

注册组件可以用Visual Studio帮我们自动注册,也可以在命令行下手动输入命令。若要使用Visual Studio来帮我们注册组件,只需在项目属性页(鼠标右键项目名称,在下拉菜单中选择“Properties(属性)”)的Build标签页中把Register for COM Interop项打上勾,然后再build项目就可以了。如下图所示:

此外,我们也可以先build项目,然后通过命令行的方式注册组件。只需要使用regasm.exe在VS2008命令行下输入如下命令即可:

regasm assemblyname.dll /tlb /codebase

该命令会为我们注册组件,生成并注册对应的type library文件。其中assemblyname.dll是项目构建生成的程序集文件。

3. 创建非托管客户端

使用托管语言创建并注册了组建之后,我们就要使用非托管语言来尝试通过COM Interop调用组建中的方法了。首先,在Visual Studio 2008中创建一个Visual C++ Win32 Console Application,取名为MyNatvieClient,并将组建生成tlb文件拷贝至该项目的源代码目录中。然后在MyNativeClient.cpp中输入如下代码:

  1. #include "stdafx.h"  
  2. #import "mscorlib.tlb" no_namespace  
  3. #import "MyManagedServer.tlb" no_namespace   
  4.   
  5. int _tmain(int argc, _TCHAR* argv[])   
  6. {   
  7.   
  8.     ::CoInitialize(NULL);   
  9.   
  10.     // Get CLSID for CoCreateInstance   
  11.     const OLECHAR lpszProgID[] = OLESTR("MyManagedServer.ManagedFooClass");   
  12.     CLSID clsid;       
  13.     HRESULT hr = CLSIDFromProgID(lpszProgID, &clsid);   
  14.     if(SUCCEEDED(hr))   
  15.     {   
  16.         printf("CLSIDFromProgID Succeeded \n");   
  17.         IDispatch* ppv = 0;    
  18.         HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&ppv);   
  19.   
  20.         if(SUCCEEDED(hr))   
  21.         {   
  22.             printf("CoCreateInstance Succeeded \n");   
  23.   
  24.             // Get DispId for Invoke   
  25.             DISPID dispid;   
  26.             const LPOLESTR szMember = OLESTR("PrintFoo");   
  27.             HRESULT hr = ppv->GetIDsOfNames(IID_NULL, (LPOLESTR*)&szMember,1,LOCALE_SYSTEM_DEFAULT,&dispid);   
  28.             if(SUCCEEDED(hr))   
  29.             {   
  30.                 printf("GetIDsOfNames Succeeded \n");   
  31.   
  32.                 // There&apos;s no parameter to pass   
  33.                 DISPPARAMS dispParams = {0};   
  34.                 VARIANT vtResult;   
  35.                 UINT dwArgErr;   
  36.   
  37.                 HRESULT hr = ppv->Invoke(dispid,IID_NULL,NULL,DISPATCH_METHOD,
  38.                                                         &dispParams,&vtResult,NULL,&dwArgErr);   
  39.                 if(SUCCEEDED(hr))   
  40.                 {   
  41.                     printf("Invoke Succeeded \n");   
  42.                 }   
  43.             }   
  44.   
  45.             ppv->Release();   
  46.         }   
  47.     }   
  48.   
  49.     return 0;   
  50. }  

该代码主要做了以下几件事情:

a. 调用CoInitialize进行初始化。

b. 调用CLSIDFromProgId获得对象的CLSID,因为接下来的函数将通过CLSID来创建实例。

c. 通过CoCreateInstance创建对象实例。这里创建的是一个IDispatch的对象实例。

d. 调用IDispatch::GetIDsOfNames以获得将要调用的方法的DispID,供接下来的函数使用。

e. 使用IDispatch::Invoke来调用方法。

在import type library的时候我们不仅import了组建的tlb文件,同时还import了mscorlib.tlb以避免生成的临时的tlh文件中一些类型找不到的情况。(有关此方面的问题可以参考我们团队开发人员张羿撰写的《#import从.NET DLL生成的tlb的神秘错误》)

编译通过后运行结果,可看到命令行中打印出如下信息:

CLSIDFromProgID Succeeded
CoCreateInstance Succeeded
GetIDsOfNames Succeeded
in MyManagedServer: CustomCOMClient.PrintFoo()
Invoke Succeeded

注:本文所示代码只作为实例使用。本文作者不对因代码使用不当而造成的问题负责。v

Posted Tuesday, July 22, 2008 1:51 PM by SilverlightShanghai | 1 Comments

Filed under:

现在就下载开源工具P/Invoke Interop Assistant -- 使用P/Invoke中进行签名转换的好帮手

P/Invoke Interop Assistant是一款帮助使用P/Invoke(及reverse P/Invoke)的开发人员进行托管代码与非托管代码之间签名转换的小工具。在一月份的MSDN杂志的网站上,我们曾经发布过它的第一个版本。经过整个团队的努力,现在我们终于把它搬上微软的开源网站CodePlex,和更多的开发人员共享它为开发工作带来的便捷,并提供全部的源代码,供大家参考和利用。

经常接触Interop marshalling的开发人员一定深刻的体会到marshalling的属性及规则的复杂性,而这些属性和规则也让很多刚刚接触这块领域的开发人员望而却步。对于COM Interop,我们有tlbimp.exe以及tlbexp.exe这样实用的小工具来帮助开发人员进行自动的签名转换并生成相应的文件,而对于P/Invoke来说,在这块领域几乎是片空白。这也就是我们为什么萌生出了开发P/Invoke Interop Assistant的想法。

P/Invoke Interop Assistant包含两个命令行的工具,分别对托管代码到非托管代码的签名转换进行文件批处理,以及其反向的批处理转换。它还包含了一个UI的工具,涵盖了所有的功能。使用者可以给工具指定一个有效的托管程序集文件,P/Invoke Interop Assistant就会把其中的托管代码的签名转换成非托管代码的签名显示出来,并对签名中可能出现问题的地方作出提示。对于反向转换,只要用户输入有效的非托管代码,或者在工具自带的数据库中进行选择,P/Invoke Interop Assistant就能将其转换成对应的托管代码签名。用户只要把转换后的结果进行复制,粘贴到自己的代码文件中就可以进行使用了。

关于更多P/Invoke Interop Assistant的介绍和使用方法,可以参阅随工具附带的参考手册。

要提一下的是,这个工具的开发在美国(由不同产品组的两个开发人员合作),测试及项目管理都在中国进行。这样的开发测试管理模型在我们的研发团队中其实并不多见,毕竟由于时空以及时区的不同,会给项目在交流上带来很多阻扰。好在团队成员之间默契的合作使这个工具顺利交付,并尽早的和开发社区共享。我们真切的希望可以得到更多开发人员的反馈,帮助我们对工具进行改进,使它在实际开发过程中能够发挥更大的作用!

现在就去我们的CodePlex主页下载P/Invoke Interop Assistant吧!

Posted Tuesday, June 17, 2008 3:13 PM by SilverlightShanghai | 3 Comments

Filed under:

Silverlight 2 Beta 2来了!

不知不觉,离那个“黑色”的日子已经快一个月了。我相信听到四川的地震消息,不少赤诚的中国人(包括我在内)都是眼含热泪度过那些日子的。面对这样的天灾,我们不得不感叹自己的无能与生命的无助。在地震发生后,公司马上举行了捐款,美国总部与大中华地区的员工都参与的捐款,我们很多人都将捐款的数目改了又改,虽说是尽自己的微薄之力,却总觉得自己所能做的还太少,而捐款也是我们所能付出的最好的方式了。一个月过去,再回到这个博客,觉得应该振奋一下了。生命既然脆弱而短暂,就更应该好好珍惜,用自己的方式更投入的做有意义有价值的事情。毕竟,我们必须是不断向前走的。

就让我们从一条好消息开始吧……

美国时间6月4日上午9点(北京时间6月5日凌晨0点),微软全球副总裁Soma Somasegar与微软执行主席Bill Gates在于奥兰多举行的微软全球技术大会TechED上共同宣布并展示了这周将会发布的Silverlight 2 Beta 2。回顾Silverlight初出茅庐至今,可以发现Silverlight发展的每一步都有非常大的变化和改进。这次的Silverlight 2 Beta 2也不例外。为了更大程度的为设计开发人员带来快乐的开发体验,最大程度的实现开发设计人员的设计梦想,也为了使网络应用程序更丰富多彩,应证那句“点亮网络”的宣传语,Silverlight 2 Beta 2在以下几方面都作了不同程度的改进:

1. UI框架: Beta 2所作的改进包括动画、错误处理机制、对残障人士的功能支持、键盘输入支持,并提高的性能。而且Beta 2还对Silverlight 与WPF之间的兼容性作了改进。

2. 丰富的控件:Beta 2包含了一个新的模板模型,叫做Visual State Manager。通过它,将自定义的控件做成模板将更加简单。此外,在Beta 2中,对TextBox加入了段落格式化(也就是text wrap)及滚动条的支持使得多行文字输入的功能更容易实现,对DataGrid提供了自动缩放及排序等功能,性能也获得了提升。Beta 2还加入了一个新的Tab控件,叫TabControl。而且,Beta 2中的大部分控件都是内建在运行时中的,而不是和具体的应用程序绑定,这样也使得客户端下载的数据包尽可能的小,提高传输速率。

3. 网络(Networking)支持: Beta 2中对网络支持的改进包括跨域支持、安全性,支持从web客户端的上传功能,以及服务器与客户端地双方通讯功能。

4. 丰富的基类库: Beta 2改进了线程功能,支持LINQ to JSON以及ADO.NET数据服务,并为SOAP提供了更好的支持,并改进了开发人员对网络以及数据处理的体验。

5. Deep Zoom: 在这个方面,Beta 2加入了对基于XML的Deep Zoom砖瓦图形文件格式的支持,并加入了新的MultiScaleTileSource使开发人员可以利用已有的图形数据库进行Deep Zoom功能的实现。此外,Silverlight 2 Beta 2中还加入了图形缩放状态下的事件驱动的通知机制。

自去年Silverlight发布以来,已经有不少公司选择使用Silverlight来提供他们的丰富网络体验,比如Entertainment Tonight,NBA, MSN,Hard Rock,Home Shopping Network,BMW,BBC,Yahoo! Japan,以及百度等等。而对于Silverlight 2的应用将更令人激动人心。比如从今年8月8日开始,NBC将使用Silverlight 2,通过互联网向美国所有用户提供北京奥运会的在线交互式体验,其中包含了3000多小时的在线直播与录像回放。又比如美国民主党全国代表大会的网站将利用Silverlight 2提供整整四天的在线会议直播与相关信息。对中国用户来说,有一点点遗憾的是,对Silverlight的大型应用基本上都在美国。不过通过这些实际应用,我们至少可以想象下一代的网络生活体验将是何等精彩了。

Posted Thursday, June 05, 2008 3:44 PM by SilverlightShanghai | 2 Comments

Filed under:

关于团队的一些小小变动

由于某些原因,我们与这里的博客小别了一段时间。并不是因为我们对传播Silverlight的相关知识丧失了激情,也并非这段时间没有Silverlight的相关故事,只是在研发团队内部发生了一些小小的变动,我们在根据变动调整自己,也在根据变动计划将来。

细心的朋友一定会发现这个博客的名字有一些小小的改动,CLR的概念被提了上来,也被放在了所有话题的最前面。没错,这两个月来,团队人员发生了一些小小的改变,开发及测试人员进行了重组。而我们项目关注的领域也从原先基于.NET技术的Silverlight转向更大的空间。从现在开始,我们关注的领域包括:1)CLR Interop(包括COM Interop以及P/Invoke)的底层开发,为开发人员对托管代码与非托管代码之间的调用提供更好的开发体验;2)Silverlight底层技术的开发,提高其性能及稳定性。熟悉Silverlight的朋友一定知道,Silverlight 2基于.NET技术进一步增强网络交互式应用程序的体验,而我们将来对Silverlight的研发关注点将在于其中的.NET技术的运行引擎CLR(我们称之为CoreCLR,即CLR的一个核心子集)相关的研发。因此,正确地说,原先的Silverlight上海研发团队已转型为CLR上海研发团队。但我们将会有一半的精力在Silverlight,而另一半精力在CLR Interop。

对于这个博客,就我个人而言,倾入了不少心血。我们团队中的每个人也都很喜欢用这样一种方式和阅读博客的你们进行交流,并让更多的中文阅读者获得更多CLR及Silverlight方面的信息。在多方讨论之后,我们决定沿用原来的博客空间,修改博客主题,并将博客的内容放宽至整个CLR方面的新闻、故事和技术交流。无论是CLR也好,或是Silverlight也好,不管是意见亦或建议,我们依然希望能听到你们声音。

对这两个月的“失踪”,我们深感抱歉。相信从今往后,这个博客会更多姿多彩!

项目经理(Program Manager)
郭晓颖

Posted Monday, May 12, 2008 3:35 PM by SilverlightShanghai | 6 Comments

Filed under:

MIX08,迎来Silverlight2的新时代

 

这周一,看似和往常的周一也没什么不同。我照例总结着Silverlight上海研发团队在过去一周中的工作,并思忖着怎样迎接新一周的挑战。而Silverlight上海研发团队的每个人也同样一如既往的完成计划中的任务。忽然从Redmond飞来一封电子邮件,用很大的标题写着:Silverlight 2 Beta 1 Ships!!!三个强烈的惊叹号。接着是老大们连绵不绝的祝贺信。开发工具部的部门经理徐鹏阳以及部门总监Terry Leeper也都发邮件祝贺这一次的成功,尤其肯定了我们上海研发团队在Silverlight 2 Beta1中做出的贡献。埋头工作的我们突然意识到,Silverlight 2的时代要真正来临了。(顺便普及一下什么是Silverlight 2Silverlight 2是一个基于.NET技术的跨浏览器、跨平台的插件,为互联网络带来下一代基于.NET的媒体体验和丰富的交互式应用程序。与Silverlight 1.0最大的不同就是Silverlight 2是基于.NET技术的,增强了网络应用程序的交互式体验。)

过了两天,长久以来的梦想真正变成现实。包含着我们上海研发团队心血的Silverlight 2 Beta1 (请注意是Silverlight 2,而不再叫2.0)在MIX08大会上正式对外宣布。MIX大会是微软在拉斯维加斯举办的年度盛会,大会上网络开发人员与设计人员汇聚一堂,共同探讨网络应用的新技术,展望互联网络应用的发展。互联网应用处处体现着MIX的精髓:开发人员与设计人员的相互协作是一种MIX,而日新月异不断更替的新技术更是一种MIX。这也是大会称之为MIX的由来。

今年的MIX08同样体现了它的主旨,除了Silverlight 2 Beta1以及Interop Explorer 8 Beta1的发布,新鲜出炉的开发及设计人员相应的工具Silverlight 2 Tool for Visual Studio 2008, IIS Media Pack, Expression 2也被呈现在了与会者的眼前。在大会上还宣布了一些其他重要的消息,如Windows MobileNokia的手机操作系统将也会支持Silverlight 1.0的运行。当然,最精彩而有趣的当然还要数大会上令人眼花缭乱的演示。只可惜上海研发团队没有机会出席这一年度的MIX盛典,只能与美国的同事通过图片和文字来分享产品发布的喜悦。

Silverlight 2 Beta1中的新功能我在以前的博客中已经提过,这里就不再重复了。值得提一下的是,MSDN上建立了Silverlight 2中托管代码的参考文献,我相信这对开发人员来说一定是莫大的帮助。虽然Beta1才刚刚发布,但其实研发团队早已投入到Beta2的研发任务中,有些领域的开发测试人员甚至都快走完了Beta2的里程碑。在过去的一年岁月中,我们投入更多的是对Silverlight 2最底层的技术进行研发,以及某些特性的测试。或许我们的成绩并不是那么直观,但却为保障Silverlight 2运行时各方面的性能起到了关键的作用。每次想到这里,我都不禁为自己所在的团队感到自豪。目前Silverlight上海研发团队正经历着重组,很快我们将只会关注Silverlight的最底层技术。这又是一个新的挑战。

下周一,却是一个崭新的一周。

 

于2008年3月7日

Posted Thursday, March 13, 2008 3:57 AM by SilverlightShanghai | 3 Comments

Filed under:

获取并使用通过Downloader对象下载的内容

在《Silverlight中的Downloader对象》一文中,我们已经了解了一些关于Downloader的基本概念,以及如何使用Downloader来下载文件并根据需要触发一些事件。而本文我们将看一看在下载结束后,该怎样根据需要处理下载下来的文件。

处理下载下来的文件一般都在Completed事件的事件处理函数中。大多数情况下,我们需要用Downloader下载的文件可以分为如下几类:包含Silverlight中界面元素的XAML文件或处理逻辑的js文件,各种媒体文件(如图片、视频等等),字体文件,以及包含各种类型文件的压缩包文件(.zip文件)。接下来我们就这几种类型分别说明一下。并假设我们的Completed事件处理方法名为onCompleted

1. 获取并使用下载的XAML元素

如果下载的是单个文件,而不是压缩包(.zip)的话,使用ResponseText 属性即可得到下载的文件。ResponseText表现为一个字符串,表示下载的文件名。要将下载的XAML中的对象加载到正在运行的Silverlight控件中,我们需要从下载的XAML中生成一个XAML元素对象。CreateFromXAML方法可以帮助我们实现这一点。其返回值为XAML对象的引用。

下面的这个例子即将下载的XAML加载到Silverlight控件中(假设下载的文件为描述背景画面的XAML片断)。这个例子首先查看uri属性来判断下载下来的文件是否是我们所需要的那个。调用Downloader.send()方法会将文件的URI赋予该属性。

// Completed事件的处理函数
function onCompleted(sender, eventArgs)
...
{
    
//使用uri属性保证要处理的下载的文件正确
    if (sender.uri == "background2.xaml")
    ...
{
        
// 获得下载的文件内容
        var xamlFragment = sender.ResponseText;

        
// 从XAML中创建对象
        var plugin = sender.getHost();
        
var background= plugin.content.CreateFromXaml(xamlFragment);

        
// 将创建的对象加入到根Canvas中
        var rootCanvas = sender.findName("rootCanvas");
        rootCanvas.children.add(background);
    }

}

上面的例子为xamlFragment开辟了一个存储空间,通过使用xamlFragment变量来保存ResponseText的值,然后再通过该变量创建XAML对象的引用。我们也可以使用CreateFromXAMLDownloader方法直接从下载的XAML片断中创建对象。基本用法如下:

function onCompleted(sender, eventArgs)
......
{
    
//使用uri属性保证要处理的下载的文件正确
    if (sender.uri == "background2.xaml")
    ......
{
         
var slPlugin = sender.getHost();

         
//获得XAML片断并创建XAML对象引用
         var background= slPlugin.content.CreateFromXamlDownloader(sender, "");

        
// 将创建的对象加入到根Canvas中
        var rootCanvas = sender.findName("rootCanvas");
        rootCanvas.children.add(background);
    }

}

CreateFromXamlDownloader方法包含两个参数,第一个参数表示的是Downloader对象,第二个参数表示压缩包中的文件名,如果下载的不是压缩包,则这个参数为空字符串。

获取压缩包中的某个文件 

CreateFromXamlDownloader方法中可以指明压缩包中的某个文件。比如,我们使用downloader.open("GET", "background.zip")下载了一个包含了多个描述背景的XAML文件,其中一个文件为background2.xaml,通过如下方法可以直接从background2.xaml中创建对象引用:

var background= slPlugin.content.createFromXamlDownloader(sender, "