.net程序的不同
.net程序和以往的Windows应用程序有一个显著不同的地方:它的可执行文件的组织方式,不像以往的应用程序。.net程序是由MSIL语言进行组织,运行时需要调用即时编译器(JIT)编译成本地汇编指令再来执行,好比以前的VB程序一样,是一个解释执行的过程。 与指令相对应的是数据,一部分静态数据或者说是资源,对它们来说.net程序和传统程序也大大不同。本文主要对.net应用程序资源的组成以及对它的操作进行简单分析。
托管资源说明
应用程序资源主要包括字符串、图像、声音、视频等,目前最常用的是前面两种,本文主要是以在应用bmp文件过程中的经验做一下简单说明。在过去,对应于MFC,资源以.rc文件方式组织,程序在使用资源时使用它的资源ID号做为索引,用起来很不方便,而且如果想把资源从应用程序做成一个单独的资源dll文件,无论是制作还是使用,都是一件非常麻烦的事。 .net程序在这些方面进行了改进,首先在设计阶段,它把各种资源统一保存在资源文件里,称作托管资源。这里的资源文件包括两种,一种是XML文件,一种是.resources文件。我们使用.net编程序,尤其是用VC.net编程,首要建立一个form窗体,在上面加一些菜单和按钮,然后在上面添加一些图标,这时对应窗体名还另外生成了一个.resx文件,这就是XML型资源文件。 XML资源文件是由XML标签文本组成,用托管资源编辑器把这个窗体打开,就可以看到我们添加的图标和文本。另一种资源文件.resources是以二进制方式存储资源,它的体积要比XML资源文件小得多,这个文件在设计阶段并不存在,只有VS在编译.net程序时,才会把XML资源文件转化为.resources文件,同时VS还会把XML资源文件里的资源打包进应用程序和dll文件中。 MS为什么要这么做,是否有必要做成两种资源文件形式,还有MS为实现资源打包,还在VS中添加了像托管资源编译器之类的小工具,这么不怕麻烦又是为什么?这所有的问题都指向一个最有深度的解释:服从.net战略需要。
托管资源的使用
为方便使用这些资源,需要使用VS中包含的System::Resources程序集,其中操作.resx资源文件的类有ResXResourceSet()、ResXResourceReader()、ResXResourceWriter()。操作.resources文件的类有ResourceSet()、ResourceReader()、ResourceWriter()。这些类大体作用是为前两个读资源所用,后一个为写资源用。 这是直接操作资源文件,当资源被打包进exe或dll(在.net术语中称为程序集)中之后,我们用ResourceManager类,这个类只能读资源。这里要说明一下如何引用这些资源,用最简单直接的方式是用名称引用。举个例子,如果有一个程序集a.dll,里面打包一个r.resx文件,r.resx里有一个 img.bmp文件,使用这个程序集里的img.bmp怎么办?用几句话便可以轻松解决: System::Resources::ResourceManager ^res = nullptr; Assembly ^Asm1 = Assembly::LoadFile("X:\\a.dll"); res = gcnew System::Resources::ResourceManager("a.r",Asm1); Image ^m=dynamic_cast<System::Drawing::Image^>(res->GetObject("img"));
另类使用方法
除了一些具体的细节可以查看msdn之外,再补充一些非常规的用法。 把所有的资源都放进.resx文件再打包进程序集固然是比较合乎逻辑的做法,如果要直接把资源(这里特别指的是bmp文件)放进程序集,而不经过打包这一步,是否可行?答案是没有问题。事实上MS就做了这样的事,在控件开发过程中,如果要给控件弄一个图标,可以让这个图标显示在VS的工具箱中,那就必须要给这个图标(比如一个bmp文件)起一个和控件一样的名字:(程序集名).(控件名).bmp,然后把这个图标设置为链接器的嵌入托管资源文件。具体设置的方法是,在解决方案资源管理器中,在项目名称上点右键->属性,在弹出的对话框左面一栏选择链接器->输入,然后在嵌入托管资源文件一栏中填写要嵌入的资源,如果有多个资源要嵌入,中间用逗号分隔开。设置好之后,编译,然后剩下的问题就是引用。这里,引用也不是用常规的方法,而是使用System::IO程序集中的Stream类,以及Assembly类的GetManifestResourceStream方法。具体的引用方法如下: Assembly ^assembly = Assembly::GetExecutingAssembly(); System::IO::Stream ^strm =assembly->GetManifestResourceStream("img.bmp"); Image ^m=System::Drawing::Image::FromStream(strm); 这里仅仅是对bmp文件的直接嵌入做了说明,如果读者感兴趣的话,也可以试试别的资源。 可以看出,这样的方法更直接,但并没有数据可以证明这种方法的速度和常规方法相比有多大差距,单从开发的角度来看,无论是嵌入还是引用,这种方法都是比较简洁。当然从管理的角度上这种做法不可取,效率和规范化经常是一对不可调和的矛盾。
后记:开发工具的选择
下面介绍一下在开发.net程序过程中经常使用到的两个工具,以及如何使用它们: 第一个工具是VS自带的MSIL反汇编工具,可以将程序集以树形列表的方式显示出来,也可以将程序集反汇编成IL指令文件。本文主要是用它查看托管资源的名称,以便在其它地方引用。从文件->打开开始,选择一个带的托管资源的dll文件,点打开后,双击manifest节点,弹出一个新窗口,上面就是关于各个引用程序集的说明,在其中查找.mresource,就可以找到托管资源文件名。 第二个工具是大名鼎鼎的reflector,由一名MS的员工编写,是反编译和破解.net程序必不可少的工具,在本文中主要是用它看看是否已正确地把资源文件直接嵌入到程序集中。这个工具的使用更简单,打开程序集文件后,直接点里面的Resources节点即可,如果已经嵌入资源了的话,这个目录下面直接就有这个资源。
|