Win32程序资源(3)

Monday, July 17th, 2006

  ☆ 控制菜单事件
  你可能记得,Windows的消息都是通过CALLBACK函数控制的,通常它是这个样子:WindowProc()或类似的样子。我们在上一章中用到的是这个样子:MsgHandler()。它的原形如下:
LRESULT CALLBACK MsgHandler( HWND hwnd, // window handle UINT msg, // the message identifier WPARAM wparam, // message parameters LPARAM lparam, // more message parameters};
  当一个菜单消息被送到,msg将等于WM_COMMAND,所选择的菜单项目将被包含进wparam。这就是为什么菜单的标识符不能是字符串的原因,它需要适合wparam参数。更特别的是,菜单标识符只占用wparam的低位字。WPARAM,LPARAM,int等都是32位,分高、低位字的变量。Windows提供了宏LOWORD()和HIWORD()分别来提取变量中的低位字和高位字,原形如下:
#define LOWORD(l) ((WORD) (l))#define HIWORD(l) ((WORD) (((DWORD) (l) >> 16) & 0xFFFF))
  LOWORD()宏的实际情况是,由于简单的定义为WORD,就自然的取得了低端的16位。HIWORD()函数把高端的16位向右移,然后同0xFFFF之间调用了逻辑“和”(AND),确保把高于16位的字节变为0。可能你不太熟悉>>和<<操作符号,它们是位移操作符。“<>”就是向右移动。例如,我们有一个16位的变量x,它的值是224,二进制表示为0000 0000 1111 0100。下面是一个关于位移的例子:
short int x = 244, y;y = x << 4;
Contents(内容) of x: 0000 0000 1111 0100Contents (内容)of y: 0000 […]

Win32程序资源(2)

Monday, July 17th, 2006

  ☆ 位图
  想要往程序里添加图象,通过位图资源可能是最简单的办法了。位图是Windows之本,当然提供了一些函数来处理位图,请记住,如果你使用了太多的位图,你的EXE文件将要非常巨大。在资源脚本中设置位图同图标和光标没什么区别:
[identifier] BITMAP [filename]
  有一个函数LoadBitmap(),同LoadCursor()和LoadIcon()的用法很相似,它将得到一个句柄,由于我还没有讲过图形(graphics),就不具体说函数的功能了,你可以猜一猜它是怎样工作的,一旦你得到了图形句柄,你将怎样使用它呢?更多的留待以后再讲。不要担心,现在只是要你有点儿准备。下面看看我们还应该学点儿什么。
  ☆ 字符串表格
  字符串表是我最喜欢的资源类型。正象你所想的:一个充满字符串的庞大表格。字符串表有很多用处。你可以用它存储你的文件名称,游戏中的人物对话,消息框中的文本,菜单中的文本等等。在资源脚本里建立一个字符串表很容易,就像这样:
STRINGTABLE{// entries go here}
  一个字符串表由几部分组成:一个标识字符串的数字;紧跟着一个逗号;然后是加了双引号的字符串本身。字符串表里的字符串被允许使用溢出符号。注意,字符串表本身并没有标识符,所以每个程序只能有一个字符串表。一个简单的字符串表可能象下面这个样子:
// program informationSTRINGTABLE{ 1, “3D Space Game v1.0″ 2, “Written by The Masked Coder” 3, “(C) 2000 WienerDog Software”}
  从程序的字符串表里调用字符串,将使用——你可能猜到了——LoadString()函数。这是它的原形:
int LoadString( HINSTANCE hInstance, // handle to module containing string resource UINT uID, // resource identifier LPTSTR lpBuffer, // pointer to buffer for resource int nBufferMax // size of buffer);
  函数返回的实数是字符的数量,不包括空字符,它将被赋值到程序数据段的缓冲区中去,相当于字符串的长度。如果你调用了一个空字符串或者调用失败,都将返回0。下面来看看具体参数:
  ※ HINSTANCE hInstance:同以前的一样,你所有操纵项目的句柄。
  ※ UINT uID:你想要调用的字符串的数码标识符。
  ※ LPTSTR […]

使用Win32程序资源

Monday, July 17th, 2006

Win32程序资源(1)
  简介
  通过本章题目可能你已经猜出了本章论题,我将教会你在Windows程序中使用资源。简单的讲,资源即数据,它们通常是和程序的EXE文件相关联的,但是它们又是独一无二的。首先,资源在运行过程中不能被修改。它们实际上都是只读文件,而且程序代码不能够直接访问它们。另外,资源并不在程序的数据区内。在装入时,程序资源通常在某个磁盘文件中,直到程序需要它们时才被装入。使用资源是一件很容易的事情,并且它的妙处无穷。Windows为我们提供了大量的资源类型,但我们这里只学一些最常用,最容易的:图标(icon)、光标(cursor)、位图(bitmap)、菜单(menu)和字符串(string)。此后,我还将教你建立自己风格类型的资源,使你为所欲为。
  重复一下,要想看懂本章,你得有点C语言的基础。C++有时用一用,但不影响你学习本章内容。并且我假定你已经读过了上一章内容“Windows编程基础”。我还是用Microsoft Visual C++的编译器,怎么样?出发吧!
  ☆ 资源脚本
  在进行细节之前,我们要先搞懂怎样要编译器知道它所要编译的资源类型。方法是使用称之为资源脚本的特殊文件,它是一个简单的文本文件,可以手工编辑,也可以让Visual C++自动编辑,或者你用其它的自动编辑器编辑。无论如何,资源脚本文件要有一个.rc的扩展名。大多数的脚本文件都从定义资源行开始,最简单的资源行通常要用到资源类型,就像这样:
  [identifier] [resource type] [filename]  【标识符】 【资源类型】 【文件名称】
  标识符可以用两种方式表示:一种是能表示资源意思的字符串,另一种是在资源相对应的头文件中用#define定义过的数字常量。如果你选择数字常量,这通常是一个好主意,别忘了把相应的头文件加入到你的资源脚本。资源脚本使用C语言风格的文件格式好像比较容易理解。以下是一个比较简单的资源脚本实例:
#include “resource.h”
// iconsICON_MAIN ICON myicon.ico
// bitmapsIMG_TILESET1 BITMAP tileset.bmpIMG_TILESET2 BITMAP tileset2.bmp
  好理解吧!但有一件事可能把人弄胡涂。例子中的ICON_MAIN和IMG_TILESET是字符串呢,还是数字常量?但这无伤大雅,编译器编译的时候会自己判断。如果发现在头文件中有#define的定义,那就认为是字符常量,否则,就是字符串。
  如果有些迷茫,不要紧。我将解释我们要用到的每一个资源类型。什么?觉得麻烦?OK,OK,让我们用全自动的资源插入系统吧!(在Visual C++中,在“插入”下拉菜单中,选择“资源”)我还是喜欢在记事本中用手工输入的模式,别问我为什么,我也不知道。:)现在你知道了建立资源脚本的基础知识,让我们开始进一步的行程吧!
  ☆ 图标和光标
  你每天在使用的大多数的Windows程序,都有自己的图标,简单的说,就是EXE文件同这个图标资源相关联了,独特风格的光标也是如此。你已经知道图标的脚本行样子了,光标的和它很相似,看看吧:
[identifier] CURSOR [filename][identifier] ICON [filename]
  增加了一行脚本行后,也就是意味着你的EXE文件又多了一个关联。也就是说你的EXE文件要根据标识符去相应的位置寻找相应的文件[filename]。你可以使用任何你喜欢用的图标/光标编辑器去编辑相应的文件。我通常利用Visual C++中的编辑器。
  把资源脚本做出来后,并没有完事儿,因为你还不知道怎么调用相应的资源,要想知道图标和光标是怎样在你的程序中被调用的,让我们回过头来,看一看上一章中的窗口类(windows class)文件:
WNDCLASSEX sampleClass; // declare structure variable
sampleClass.cbSize = sizeof(WNDCLASSEX); // always use this!sampleClass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; // standard settingssampleClass.lpfnWndProc = MsgHandler; // message handler […]

Windows编程基础

Monday, July 17th, 2006

Windows编程(1)
  简介
  本文目的是介绍Windows编程基础。在本文结束时,你应该能够很好的工作了,虽然可能是简单的WIindows程序。你需要有C语言的基础知识,我很少将C++的代码扩充到程序中。当然,由于Windows本身就是面向对象的,一点类的知识是不会对你有什么损害的。如果你不熟悉C++,没有关系,我想你还是能从我这里学到大部分的东西。所有的程序代码都通过了Microsoft Visual C++6.0的编译,如果你还没有合适的编译器,弄一个同我一样的好了,它还是很棒的。开动吧!
  开始
  多数的Windows程序都需要Windows.h和Windowsx.h这两个头文件,要确保使用它们。当然,你还需要其它的标准的C的头文件,象stdio.h,conio.h等。除了这些,你还会经常看到在程序的开始有这样一行代码:
#define WIN32_LEANAND_MEAN
  它表示Windows的头文件中将拒绝接受MFC的东西,这将加速你的build时间。如果你从没有打算应用MFC在你的游戏编程中,那就使用它吧。如果你以前从没有看过这种声明类型——在#define后,直接加上一个“单词”,那么它的作用就是有条件编译。看看下面的例子:
#ifdef DEBUG_MODEprintf(”Debug mode is active!”);#endif
  意思是:如果程序的开始包含#define DEBUG_MODE,那么就printf(),否则退出。这个对于你跟踪程序的逻辑错误是很有帮助的。
  WinMain()函数
  DOS下的C语言从main()开始,Windows下的C语言从WinMain()开始,一个空的WinMain()函数是这样的:
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){return(0);}
  一个函数即使什么也没做,也应该返回一个值。是的,有好多东西我们不熟悉。首先的首先,WINAPI是个什么声明?WINAPI是在windows.h头文件中定义的一个宏,它把函数调用翻译成正确的调用约定。当我们在程序中需要用到汇编语言的时候,我们在来深究它好了,记住,如果要用WinMain(),就必须要有WINAPI。
  下一步让我们来看看括号里的四个参数:
  ◎ HINSTANCE hinstance:HINSTANCE是一个句柄类型的标识符。变量hinstance是一个整数,用于标识程序实例。Windows设置这个参数的值,并把它传递给你的程序代码。很多Windows函数都要用到它。
  ◎ HINSTANCE hPreInstance:你不用担心这个参数,它已经被废掉了。它只是为古老的Windows版本服务的。你将还会看到类似的情况。
  ◎ LPSTR lpCmdLine:是一个指向字符串的指针,它仅在程序名是从DOS命令行输入或是从Run对话框中输入时才起作用。因此,很少被程序代码所用。
  ◎ int nCmdShow:决定了窗口在初始显示时的状态。Windows通常给这个参数分配一个值。通常是SW_打头的一个常量。例如SW_SHOWNORMAL表示默认状态,SW_MAXINIZE或SW_MINIMIZE分别表示最大和最小模式等等。
  消息
  当你在DOS下编程的时候,你不必担心其它程序的运行,因为DOS是独占模式。但你在Windows平台上编程时,你不得不考虑其它正在运行的程序。鉴于此,Windows通过“消息”来连接操作申请和具体操作。简单的说,就是我们指示程序或程序本身向Windows发出诸如移动窗口、放大窗口、关闭窗口等地申请,Windows再根据申请,考察实地情况,拒绝或发出指令,让程序(计算机)作出相应的动作。再例如,鼠标随时向Windows发出消息,汇报光标位置,左键或右键是否按下等,Windows再根据消息作出相应的反应。总之,无论何时,Windows都要随时掌控所有的消息,而且,Windows是一直不断地接收到各种消息。
  这种功能是通过一种被命名为CALLBACK函数类型实现的。不用害怕,消息的传递来,传递去都是由Windows自己完成的,你只要声明一个CALLBACK函数就可以了,就像WINAPI用在WinMain()前一样。如果还没有明白,不要紧,往下看你就明白了。现在,我要离开这个话题一会,因为你只有先建立窗口(Windows),传递消息才有可能实现。
  窗口类
  现在谈论一点C++的知识,因为要想建立一个窗口,你就得先建立一个窗口类。窗口类包含所有的有关窗口的信息,如用什么样的鼠标符号,菜单样式等等。开发任何一个窗口程序,都离不开窗口类的建立。为了达到此目的,你必须填写WNDCLASSEX结构。EX的意思是“扩充”的意思,因为有一个老的结构叫作WNDCLASS,这里,我们将使用WNDCLASSEX结构,它的样子如下:
typedef struct _WNDCLASSEX {
UINT cbSize;UINT style;WNDPROC lpfnWndProc;int cbClsExtra;int cbWndExtra;HANDLE hInstance;HICON hIcon;HCURSOR hCursor;HBRUSH hbrBackground;LPCTSTR lpszMenuName;LPCTSTR lpszClassName;HICON hIconSm;} WNDCLASSEX;
  这个结构有不少成员,讨厌的是,你必须为窗口类设置每一个成员。莫发愁,纸老虎一个。让我们来个速成。
  ※ UINT cbSize:指定了以字节为单位的结构的大小。这个成员是通过sizeof(WNDCLASSEX)实现的。你将会经常看到它,尤其是你使用了DirectX。
  ※ UINT style:指定了窗口的风格。它经常被以CS_打头的符号常量定义。两种或两种以上的风格可以通过C语言中的“或”(|)运算符加以组合。大多数情况我们只应用四种风格,出于对文章长度的考虑,我们只列出这四种。若你还需要其它的,到MSDN里找一下好了。别告诉我你用的不是Visual C++啊!
  ◎ CS_HREDRAW:一旦移动或尺寸调整使客户区的宽度发生变化,就重新绘制窗口。
  ◎ CS_VREDRAW:一旦移动或尺寸调整使客户区的高度发生变化,就重新绘制窗口。
  ◎ CS_OWNDC:为该类中的每一个窗口分配一个唯一的设备上下文。
  ◎ CS_DBLCLKS:当用户双击鼠标时向窗口过程发送双击消息。
  ※ […]