.net程序资源组件浅析

论坛 期权论坛 脚本     
已经匿名di用户   2022-5-29 19:21   1408   0

.net程序资源组件浅析

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()。这些类大体作用是前两个为读资源用的,后一个为写资源用的。这是直接操作资源文件,当资源被打包进exedll(在.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节点就行了,如果已经嵌入资源了的话,这个目录下面直接就有这个资源。

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP