Win32编程API 基础篇 -- 5.使用资源
使用资源
你可能想参考教程结尾的附近,为了获得跟VC++和BC++资源相关的信息。
在我们讲得更加深入之前,我将大致讲解一下资源的主题,这样在每个小节中我就不必再去重讲一遍了。在这一小节中,你不需要编译任何东西,这里的代码只是个例子。
资源是以二进制的格式存储在你的可执行文件内部的预定义的数据,在资源脚本中我们创建资源,所谓的资源脚本就是有”.rc”扩展名的群文件,商业编译器通常有一个视觉资源编辑器老让你在不需要手动编辑的情况下创建资源,但很多时候手动这是唯一的创建资源的方法,如果你的编译器没有视觉编辑器的话,或者它很糟糕,不支持你所需要的具体功能。
很不幸的是不同的编译器套件处理资源的方式是不一样的,我将竭尽所能来解释一般情况下资源工作的共同特征。
资源编辑器附带MSVC++使它很难手动编辑资源,因为它执行一个专有格式,并且如果你手动创建了一个资源,整个文件都可能被完全损坏,所以一般情况下你不应该打扰资源文件的创建,但是明白如何手动修改它们有时又是很有用的。另一个比较蛋疼的就是MSVC++将默认资源头文件的命名为“resuorce.h”即使你想使用其他命名。为了简单起见我将以这个文档中数据为基础,但在附录中会向您展示如何在编辑器中进行修改。
首先,让我们看一段非常简单的资源脚本,一个图标。
1 #include "resource.h"
2
3 IDI_MYICON ICON "my_icon.ico"
这是整个的文件,IDI_MYICON是资源标识符,ICON是类型,“my_icon.ico”包含资源文件的扩展名,在所有的编译器中都应该生效。
#include "resource.h"跟什么相关呢?嗯,你的程序需要一种定义图标的方式,最好的方式就是分配一个唯一的ID(IDI_MYICON),我们可以通过创建一个“resource.h”文件然后在我们的资源脚本文件和源代码文件中引入。
1 #define IDI_MYICON 101
正如你所看到的,我们指定了IDI_MYICON的值为101,我们可以不使用定义直接使用101当引入图标的时候,但是IDI_MYICON引入的写法更加清爽,并且在大量引入资源文件的时候更容易记住。
现在让我们添加一个菜单资源:
1 #include "resource.h"
2
3 IDI_MYICON ICON "my_icon.ico"
4
5 IDR_MYMENU MENU
6 BEGIN
7 POPUP "&File"
8 BEGIN
9 MENUITEM "E&xit", ID_FILE_EXIT
10 END
11 END
同样的IDR_MYMENU是资源的名称而MENU是资源类型。现在好点,看到了开始和结束了么?一些资源编辑器或编译器使用“{”和“}”分别用来替代BEGIN和END,如果你的编译器两个都支持随意选择其中一种方式。如果它只支持其中一种或者其他方式,你需要进行必要的更换工作保证正常使用。
我们也添加了一个新的标识符ID_FILE_EXIT,所以为了在我们的程序中使用,我们需要把它添加在我们的资源头文件resource.h中。
1 #define IDI_MYICON 101
2 #define ID_FILE_EXIT 4001
在大型的项目中生成和跟踪这些ID是一件很蛋疼的事,这就是大多数人使用为你完成这些工作的视觉资源编辑器的原因。但它仍然会时不时弄糟,你可能最终会遇到多个项目相同ID或类似的问题,这时候手动调整有利于解决问题。
现在下面有一个如何在你的程序中使用资源的栗子:
1 HICON hMyIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYICON));
LoadIcon和许多资源使用函数的第一个参数就是当前窗口实例的句柄(这个在我们的WinMain()中被给出了,同时也可以使用我们前面提到的GetModuleHandle()来得到这个句柄)第二个参数就是资源的标识符。
你可能会想MAKEINTRESOURCE()是用来干嘛的,也可能会想当我们要传递给LoadIcon()资源ID参数时,为什么会取一个LPCTSTR类型的参数而不是用UINT。所有的MAKEINTRESOURCE()做的事情就是把一个整型的ID变成LPCTSTR类型,而这是LoadIcon想要的参数类型。这就引出了定义资源的第二种方式,就是直接使用字符串,几乎不会有人再这样做,所以在这里我们简略说说,但是基本上如果你没有用#define的方式为你的资源指定ID,那么这个资源名就会被解析成字符串,在你的程序中可以这样子引用:
1 HICON hMyIcon = LoadIcon(hInstance, "MYICON");
LoadIcon()和其他加载资源的API可以区分传递的是一个资源ID还是一个指向字符串的指针通过检查这个值的高16位,如果高16位是0(整数的范围是0到65535)将被认定为传入的是一个资源ID,这很有效如果你限定你的资源ID在65535以下,这个应该够用了除非你有超多资源,所以应该没有问题;如果高16位不是0那么就会被认定为是一个指向字符串的指针,加载资源的函数就会通过资源名去查找资源。永远不要依赖于API去实现这个除非它在文档中被明确规定。
例如,这并不适合像ID_FILE_EXIT菜单命令,因为他们只能是整数。
PS.由于本人英文水平所限,只能翻译到这个程度了,有纰漏还望多多指出,附上本篇翻译的英文原版教程地址:http://www.winprog.org/tutorial/resources.html