`
lingzantia
  • 浏览: 147015 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

[翻译]-Windows CE 程序设计 (3rd 版)--4.5 资源

阅读更多

翻译tellmenow

资源
资源是应用程序或DLL的一个只读数据段,在模块被编译后,资源被链接到模块中。资源为开发者提供了一个与编译器无关的位置,用来存储常量数据,例如对话框、字符串、位图、图标以及菜单。因为资源并不编译在程序里,所以改变它们并不用重新编译程序。

您可以通过构造一个描述资源的的ASCII文件--资源脚本--来创建资源。ASCII文件的扩展名叫RC。您可以用资源编译器来编译该文件,每个Windows开发工具的制造者都提供该编译器。随后您可以用链接器把该文件链接到编译后的可执行文件中。现在,这些步骤被厚厚的可视工具层掩盖了,但功能依然保持相同。例如,即使很少还有程序员会直接看资源文件,但eVC++依然创建和维护一个ASCII资源文件(RC)。

对编程书籍的作者来说,决定如何选择工具是一件很痛苦的事情。一些工具侧重于高级指令,谈论菜单选择,描述对话框。另一些则使用ASCII文件和命令行编译器,为读者展示如何从头开始构建程序的所有组件。我可以描述如何使用可视化工具或者如何为资源创建基本的ASCII文件。在本书中,我着重在ASCII资源脚本级别,因为目标是讲授Windows CE编程,而不是如何使用特殊的工具集。我还将演示如何通过创建和使用ASCII RC文件来增加菜单等。但在本书后面与资源文件不相关的地方,我不会总是将RC文件包含在清单里的。当然,这些文件会包含在附书的CD里。

资源脚本
创建资源脚本同使用记事本创建一个文本文件一样容易。使用的语言简单,有些像C语言。使用//来标记注释行,使用#include来包含文件。

菜单模板示例如下:
//
// A menu template
//
ID_MENU MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Open...", 100
MENUITEM "&Save...", 101
MENUITEM SEPARATOR
MENUITEM "E&xit", 120
END
POPUP "&Help"
BEGIN
MENUITEM "&About", 200
END
END

开头的ID_MENU是资源的ID值。作为可替代的方式,该ID值可以用字符串来标记资源。用ID的方式可以提供更紧凑的代码,而使用字符串方式则可以在应用程序从源文件里装载资源的时候提供更好的可读性。接下来的关键字MENU则标记了资源的类型。菜单用POPUP作为开始,指出该菜单项File实际上是一个绑定到主菜单的弹出式级联菜单。因为式菜单里的菜单,所以它也使用BEGIN和END关键字来包围对File菜单的描述信息。字符&告诉Windows下一个字符是菜单项的键盘快捷符。在菜单项被显示的时候,其后的字符会被Windows自动加下划线。当用户按下Alt键和该字符,菜单项会被选择。菜单里的每一项被关键字MENUITEM标记,后面跟随的是用在菜单中的字符串。在Open和Save字符串后的省略号是Windows 界面习惯,用来告诉用户选择该项会显示一个对话框。Open, Save, Exit和About菜单项后的数字是菜单ID值。这些值用在WM_COMMAND消息中来标记菜单项。用定义在通用包含文件里的值替代这些值,使它们和WM_COMMAND处理代码中的值一致,这是一个好的编程习惯。

表4-2列出了您可以在资源文件中找到其它资源类型。DISCARDABLE关键字是可选的,用来告诉Windows如果没有足够的内存时,这些资源可以从内存中丢弃。剩下的是BEGIN和END关键字,使用括号{}也是可以的。

表4-2:资源编译器支持的资源类型

Resource Type

Explanation

MENU

Defines a menu

ACCELERATORS

Defines a keyboard accelerator table

DIALOG

Defines a dialog box template

BITMAP

Includes a bitmap file as a resource

ICON

Includes an icon file as a resource

FONT

Includes a font file as a resource

RCDATA

Defines application-defined binary data block

STRINGTABLE

Defines a list of strings

VERSIONINFO

Includes file version information

[*]The SHMENUBAR resource type used by the Pocket PC is actually defined as RCDATA inside a wizardgenerated include file.

图标
既然我们在使用资源文件,那么修改Windows CE Shell用来显示程序的图标就是一件很容易的事情。使用您喜欢的图标编辑器创建图标,并用以下语句加到资源文件:ID_ICON "iconname.ico"。
当在Windows Explorer中显示程序的时候,Windows在EXE文件中查找,从资源列表中找到第一个图标来代表该程序。

让图标代表应用程序的窗口可能略微有些烦琐。Windows CE用工具条上一个小的16*16像素的图标代表左面上的窗口。在桌面版的Windows里,可以用RegisterClassEx函数将小图标和窗口绑定到一起,但在Windows CE里不支持该函数。作为替代,图标必须显式装载和分配给窗口。下面的代码片段为窗口分派了一个小图标。

hIcon = (HICON) SendMessage (hWnd, WM_GETICON, FALSE, 0);
if (hIcon == 0) {
hIcon = LoadImage (hInst, MAKEINTRESOURCE (ID_ICON1), IMAGE_ICON, 16, 16, 0);
SendMessage (hWnd, WM_SETICON, FALSE, (LPARAM)hIcon);
}

第一个SendMessage调用是用来获取窗口当前分配的图标。wParam中的FALSE值指出要查询窗口的小图标。如果返回0,表示没有图标分配过,就调用LoadImage函数从应用程序资源中装载一个图标。LoadImage函数可以用文本字符串或者ID值来标记要装载的资源。在当前情况下,MAKEINTRESOURCE宏用来为函数生成一个ID值。在Windows CE中,被装载的图标必须是16*16的图标。LoadImage不会把图标调整到要求的尺寸。在Windows CE下,LoadImage只限于从资源中装载图标和位图。Windows CE另外提供了SHLoadDIBitmap函数用于从文件中装载位图。

不同于其它版本的Windows,Windows CE将窗口图标存储在一个基础类里。所以如果在一个应用程序里的两个窗口具有同样的类,它们将使用相同的窗口图标。这里有一个忠告:窗口类是针对应用程序特定实例的。如果您有应用程序FOOBAR的两个不同实例,它们有不同的窗口类,所以它们可能有不同的窗口图标,即使它们使用相同的类信息进行的注册。如果FOOBAR的第二个实例有两个同类的窗口被打开,这两个窗口会使用同样的图标,同FOOBAR第一个实例中的窗口图标无关。

加速键
可以装载的另一种资源是键盘加速键表。通过使用该表,Windows允许开发者为应用程序中的特定菜单或控键指定快捷键。具体来说,键组合用来产生发送到窗口的WM_COMMAND消息,而加速键就是为键组合提供了一个直接的方法。这些加速键不同于那些用来访问File菜单的类似Alt-F的键组合。只要File菜单项字符串中使用"&"字符,例如"&File",File菜单键组合就会被自动处理。虽然通常键盘加速键被用来模拟菜单操作,例如使用Ctrl-o来打开一个文件,但键盘加速键是独立于菜单或者其它控件的。

下面是一个简短的资源脚本,定义了一对加速键。
ID_ACCEL ACCELERATORS DISCARDABLE
BEGIN
"N", IDM_NEWGAME, VIRTKEY, CONTROL
"Z", IDM_UNDO, VIRTKEY, CONTROL
END

和菜单资源一样,该结构以一个ID值做为开始。该ID值后面是资源的类型,随后是可选的discardable关键字。加速键表的入口项包含标记加速键的字母,其后是命令ID值,VIRTKEY表示字母实际上是虚拟键值,CONTROL关键字表示需要Ctrl键与加速键一起按。

只是在资源文件中有加速键表还远远不够。应用程序必须装载加速键表。对从消息队列中取出的每个消息,应用程序还要检查是否有键入了加速键。幸运地是,通过简单修改主消息循环就可以完成这些。下面是一个修改后的处理键盘加速键的主消息循环。

// Load accelerator table.
hAccel = LoadAccelerators (hInst, MAKEINTRESOURCE (ID_ACCEL));

// Application message loop
while (GetMessage (&msg, NULL, 0, 0)) {
// Translate accelerators
if (!TranslateAccelerator (hwndMain, hAccel, &msg)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}

主消息循环中的第一个不同点是使用LoadAccelerators函数装载加速键表。之后,每个消息从消息队列中取出后,都调用TranslateAccelerator。如果该函数转换了消息,返回值是TRUE,这将跳过标准的TranslateMessage和DispatchMessage循环体。如果没有转换,循环体就正常执行。

位图也可以被存储为资源。Windows CE中使用位图资源会略微不同于Windows的其它版本。在Windows CE里,调用LoadBitmap来装载位图的只读版本。这意味着当位图被选择进设备环境变量后,该图象就不能被这个DC里的其它绘制操作所修改。该函数原型如下:

BITMAP LoadBitmap(HINSTANCE hInstance, LPCTSTR lpBitmapName);
要装载一个位图资源的可读写版,可以使用LoadImage函数。

字符串
使用字符串资源,将和语言相关的信息放到编译的代码之外,是一种减少应用程序内存使用的好方法。应用程序可以调用int LoadString(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax)来从资源中装载字符串。uID是字符串资源的ID,lpBuffer指向接收字符串的缓冲区,nBufferMax是缓冲区的大小。在Windows CE里,为了节省内存,LoadString有一个新特性。如果lpBuffer是NULL,LoadString返回一个指向字符串的只读的指针作为返回值。可以简单地把返回值转换成一个指针,并在需要的时候使用该字符串。字符串的长度位于字符串起始位置之前的一个字里。需要注意的是,默认情况下,资源编译器从字符串资源中去除结尾的0。如果您想直接读取字符串资源,并让它们以0做终结符,那么您可以使用-r命令行开关来激活资源编译器。虽然我将在第七章涉及为了节约内存而采取的内存管理和策略,但是这里还是有个快速提醒:从资源文件中装载许多字符串到内存里并不是一个好的方法。这将使用资源和RAM里的内存。如果您同时需要很多字符串,使用LoadString的新特性返回一个直接指向资源自身的指针会是一个比较好的策略。作为替换,您可以用编译到程序只读段里的字符串。您失去了单独字符串表的优势,但您减少了内存使用量。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics