第二章 建立一个应用程序
无论你是一位编程专家还是初学者,通过本章的学习,你都将很快的学会Palm OS的编程。在这个过程中你首先要创建一个能稳定工作的开发环境。值得一提的是,开发环境并不仅仅是一些编程工具的简单组合,它更是一个能协助开发者更好完成工作的系统结构。一旦源代码能够在开发环境中正常的编译并运行,这就意味着你迈出了整个程序编写过程中最重要的一步。在程序以后的修改过程中,就是一些其它的尝试和寻找B UG的工作了,当然完成这些工作也都是要在开发环境中反复调试的。
在简单复习一下Palm OS应用程序的基本结构后,我们就将创建一个这样的开发环境。然后我们将仔细研究资源编程的实质和Palm OS的代码。我们最后得到的将是一个简单而又实用的Palm OS应用程序。
编程环境
我们几乎全部使用C语言来编写应用程序代码,因为用C编写的Palm OS应用程序开销是最小的。书中的大多数例子都利用了Metrowerks Code Warrior编程环境。一般情况下,我们假定你使用的计算机操作系统是Windows。在所附光盘中,包含了一个免费的Metrowerks Code Warrior Lite版本,可以在Windows 9x和NT下运行。
用Mac作为开发平台
如果你使用的是Mac操作系统,那么你就需要做更多的工作,毕竟例子都是为Windows操作系统编写的。当然,在所附光盘中也提供了Mac版本的M etrowerks Code Warrior Lite。事实上,Mac版本和Windows版本的Code Warrior是很相似的。
对C语言应知道多少
在开始做本书的练习以前,假设你已能用C语言编写简单的程序。我建议你至少拥有一本有关C语言的好书。如果还没有的话,Herbert Schildt编写的《Teach Yourself C》(Osborne/McGraw-Hill,1997)是一个很不错的选择。
Palm OS应用程序的剖析
Palm OS的C语言编程和普通的C语言编程非常的相似。源代码被编译,并和一些控制Palm设备内部运行机制的库文件连接到一起。图2-1展示了一个P alm OS可执行程序是如何通过各种不同文件编译和连接后得到的。
另外,资源文件是被单独编译和连接的。它们用来表示程序中的图形元件,诸如窗体、按钮、编辑框等等。很多现代的图形应用程序环境如M ac OS和Windows也是用资源文件来描述它们的用户界面的。
每一个窗体都包含大量的按钮或其它控件。在资源文件中包含了应用程序所有窗体的所有信息。你可以通过Metrowerks Constructor(构造器)编辑资源文件——添加、改变或删除窗体和按钮等。
y深入什么是控件?
控件就是用来接受用户信息的屏幕上的特殊区域。它可以从简单的如按钮(通过手指或输入笔激活)到复杂的如窗体(其中包含了各种不同的其它控件)。你可以通过资源编辑器创建和定义控件。
Palm OS的存储器
传统的存储器一般分两种:一种是快速但掉电后丢失数据的RAM,另一种是低速但永久保存数据的硬盘存储器。大多数计算机在将数据从诸如硬盘、C D等存储设备转移到RAM时花费了大量的时间。
在这方面Palm的存储器较之传统计算机设备有着很大的区别,它使用的是另一种形式的存储器:快速且可永久保存的存储器。这使得它操作数据的速度有了极大的提高。同时P alm是没有文件系统的,它的工作原理实际上就是把存储器组织成数据库的形式。从基本上来说,存储器中的所有东西都被保存成数据库形式。甚至应用程序也是以这种形式保存的。应用程序所在的数据库就是由可执行的代码以及其它在资源编辑器编辑过的资源来填充的。
对于传统的计算机应用程序,为使程序更快的运行,不可避免的存在着多个数据块的拷贝,如一个拷贝在RAM中,一个拷贝在硬盘上。但在P alm OS中,你如果移动数据或制作拷贝却完全没有必要,因为不管你的数据块在什么地方,Palm OS都能直接的访问到它,这是把存储器组织成数据库形式的好处之一。
图2-1:一个Palm OS 应用程序是怎样产生的源文件(Source File *.C) 文本编辑器(Text Editor) 头文件(Income File *.H) 编译器(Compiler)库(Librarian)对象文件(Object Files .OBJ 或.O) 资源编辑器(Resource Editor)库文件(Library Files *.LIB) 连接器(Linker) 资源文件(Resource Files *.RSRC) 可执行文件(Executable File *.PRC)
Palm OS应用程序的执行和调试
Palm一次只能执行一个程序。你可通过选择主菜单中的应用程序图表或按下在Palm底部的四个按钮的其中一个来运行程序。一旦一个程序开始后,它只在另一个程序开始时才会中止。当你关闭P alm后,程序停止,但再次打开后,程序将在断点处继续执行。
当你测试程序时,Code Warrior开发环境会运行一个叫Console的程序来初始化调试信息。Code Warrior将把代码及其它调试信息传给Console,然后Code Warrior利用Console来执行程序、单步测试、设置断点、检查数据等等。当你调试完程序后,最好重启一下你的Palm,即按下调试面板上的X 按钮或用push-pin(或其它尖的东西)插入Palm背后的洞来重启。这样,你就可以把保存在存储器工作区域的数据清除掉。
Console文件是作为隐藏文件保存在Palm中,你并不需要为调入Console而做任何事情。
深入什么是调试器呢?调试器就是用来寻找和修改程序中存在问题的计算机应用程序。就Code Warrior和Palm OS来讲,调试器内嵌在PC中并与Console文件相关联用来检查程序运行时是否有什么问题。调试器可让你一步一步的观测代码和变量。你还可以设置断点来观测当程序运行到此处时会出现什么问题。
开发环境的安装
根据随书光盘所指出的步骤安装 Code Warrior。Code Warrior Lite和Code Warrior几乎一样,但为了督促某些程序员使用正版软件,它在程序的大小和复杂程度上有一定的限制。如果要成为一个真正的开发人员的话,我认为还是购买一套完全版的C ode Warrior为好。即便你不想立即购买,你在读完本书后也该拥有一套。
在Windows计算机上安装完Code Warrior或Code Warrior Lite 后,你或许会发现你的构造器(constructor)还存在问题,那就是你所建窗体上的字体太大了。你须进行以下步骤以使你的构造器正常运行:
1. 找到包含操作系统的文件夹,一般情况下在C:盘上的Windows目录下;
2. 打开Windows文件夹;
3. 打开Fonts文件夹;
4. 关闭Fonts文件夹;
5. 关闭Windows目录;
现在你的构造器就可正常工作了。
IDEs和Code Warrior
当你需要把程序思想转变为现实时,一个好的编程环境显得尤为重要。很早以前(在打孔卡过时后和Turbo Pascal出现之前),你要用一个文字编辑器、一个编译器、一个连接器来构成你的编程环境,这或许就得用到三个不同公司的产品。Palm OS的免费编译器——gcc就是这样的一个例子。首先用文字编辑器产生代码文件和资源文件,然后用gcc工具单独的编译、连接和调试代码。
90年代初,出现了一种新的编程环境——IDE(集成开发环境),它是一种集编辑、编译、连接、调试于一体的开发环境。Code Warrior就是这样一种编程环境,这样就为你节省很多时间和精力,以免你为在各个环节间不停的转换;并且,你也不必再为建立自己的各个开发环节而浪费时间,因为所有的工具都被集成在一起了。
检查你的开发环境
如果你能够保证硬件和软件衔接正常,以后就能节省很多时间,特别是对于Palm OS这样的内嵌环境——编译、连接和程序的运行不在同一个机器上。我想再没有比遇到问题时不知道问题出在开发环境、硬件还是自己的代码上更恼人的事了。经过多年的编程实践,我尽量使自己避免这些不定因素的影响。下面就讲讲如何一步步检查你的开发环境:
1. 如果你还什么都没有做的话,那么第一步就是在你的PC上安装能和Palm通讯的软件Hotsync。
2. 使你的Palm设备与PC保持同步;
小技巧:
如果你的设备不能同步,可尝试下面的几种方法:确保你的串行通讯接口所插的PC端口与HotSync软件中选择的串行口是同一个;确保你所选的端口在开始通讯时不被其它的进程占用(这与使用M odem是同样的道理); 根据帮助中的提示,检查你的计算机是否存在硬件冲突,这也会使你的串口无法正常工作; 尝试其它的串行端口,如果有的话; 按Palm设备后面的重启按钮,重启Palm设备。
注意: 如果你的Palm设备不仅仅是用于开发,那么在调试之前,一定要确保Palm与PC的数据同步,否则有可能导致Palm原有的数据丢失。
3. 开始调试之前,在PC上HotSync图标上单击右键,选择弹出菜单上的Exit退出HotSync。由于HotSync在运行时独占了Palm设备的连接通道,不关闭H otSync就不能下载代码或调试,所以这一步是完全必要的。但如果你忘记了,情况也不会太严重,Code Warrior将弹出一个漂亮的消息框提示你关闭HotSync。
4. 运行Code Warrior集成开发环境(IDE);
5. 选择File | New;
6. 从Project选项卡上选择Palm OS 3.1;
7. 通过Set按钮设置目录路径;
8. 键入工程名称Starter;
注意:把你的例程及将来的程序放入独立于Code Warrior目录树的文件夹中是个很好的办法。 因为这样可以使你轻松的备份和查找。而且,当你需重装Code Warrior时就不会由于疏忽而把你辛苦编写的程序删掉了。别问我为什么想起来告诉你这些,那是令人不快的经历。
9. 在PC上,选择Project | Enable Debugger;
10. 在PC上,选择Project | Debugger或按F5编译连接工程;
11. 把Palm设备设置为Console模式。最简单的方法是利用find,删除find输入框中原有的文字并输入快捷符号。快捷符号很像连写的小写字母“l ”,你在输入区上画一个连写的“l”以产生快捷符号。然后写一个句号(在输入区轻击两下)和数字“2”。在你这样做后,你会发现Pa lm设备会发出声音并且所画的内容将消失。图2-2显示了把Palm设备设置为Console模式所要画的图形;
图2-2 为了把Palm设置到Console模式所要画的内容Cursive L: 草体的英文小写字母 “l”Two Taps: 两次点击Number Two: 数字2
12. 在PC上,单击OK把应用程序下载到Palm上。在Palm上将出现如图2-3的对话框;
13. 单击Palm上的OK。现在你就可以从函数PilotMain()的第一行开始调试程序了;
14. 在PC上,单击“ “或按下Ctrl-R运行应用程序;
15. 在Palm上,运行应用程序,屏幕上会出现一个空白窗体。按下“菜单图标”将产生菜单栏。在菜单栏上有一个可选条目,当选择后会出现另一个带有O K按钮的窗体。如果你按下OK按钮,将回到原始的窗体;
16. 在PC上,按下调试窗口的X按钮重启Palm 。(见图2-4。)如果你已关闭了Palm的电源,请重新打开再按下X按钮。这样做将重启Palm并使之处在console关闭的正常状态。也可以通过使用图钉或其它尖的东西按下P alm背面的Reset按钮。
如果你能正确走到这一步,就应该知道你的开发工具和下载环境已经能使得一个叫Starter的应用程序正常运行了。你可以把这个程序常备身边,以便当古怪离奇的东西攻击你的计算机时(相信我,即使你是我们中最幸运的,“厄运”也是有可能光顾你的),再用此程序检查你的开发环境。
当你查看Palm上的应用程序区时,就会发现多了一个叫Starter的应用程序。如果你用的是Palmed或更高版本,可选其中的Apps | Delete将下传的应用程序删掉。
生成工程
现在到了着手生成自己的工程的时候了。在这个工程中,有一个按钮上面写有“Hello”。我们可以像建立Starter程序那样生成这个工程,删去S tarter程序原有的代码和资源而用自己的新的代码和资源将之代替。你可以通过改变工程的设置使之自动生成。很多设置比较有趣,它们有直接的答案,况且在S tarter应用程序中已经设置好了。所以,这并不存在很多困难:
1. 运行Code Warrior集成开发环境;
2. 选择File | New;
3. 在Project选项卡中选择Palm OS 3.1;
4. 按下Set按钮选择目录;
5. 单击OK;
6. 给工程起名叫Hello;
注意:
你可以把有用的文献放在顶级目录或一个特殊的文献目录,以便自己和别人能很容易的找到。我在保留应用程序以备后用时,就经常放在一个叫i deas的目录中。当想添加这样的文件时,可选择“Project | Add Files”。注意应把文件类型设为All Files以便能看见文献文件。
7. 单击AppSource树使之打开;
8. 右击Starter.c并选Delete。这是原来Starter的代码,你应该用你自己的代码将之代替;
9. 单击AppResources树使之打开;
10. 右击Starter.rsrc并选Delete。这是包含原来Starter程序中有关窗体和控件的规划信息。你也应该用你自己的资源文件将之代替;
11. 进入Windows浏览器,找到新建的工程文件夹,它应该叫Hello。在这个文件夹里面,还有一个文件夹叫Src。打开此文件夹,里面是原来S tarter程序中的源文件,全选并删除。在下一部分中,你将为Hello程序建立新的源文件,它们就保存在这里。
生成资源
Palm OS资源在本质上和为Mac和Windows生成的资源是相同的,但更加简单。由于资源是来自于RezEdit的资源格式,所以它更接近Mac的资源。P alm OS程序的界面叫做窗体。为产生这个简单的“Hello”程序,你应该建立一个上面有一个按钮的单一窗体。
步骤如下:
1. 运行Palm上构造器,这是Metrowerks的资源编辑器。在Code Warrior中也会发现相同的菜单;
2. 选择File | New Project File。这样将产生一个空的资源文件。现在的工程属性取缺省就行了,在下面的章节会详细讲到它们还能做什么;
3. 改变Application Icon Name为工程名称“Hello”;
4. 在Resource Type and Name列表箱里选中Forms行;
5. 选择Edit New Form Resource或者按CTRL-K创建一个新的窗体。新窗体将出现在Forms行并被命名为“untitled”;
6. 单击name,出现编辑框后,取名字为“Hello”;
7. 双击窗体打开,在下面的章节中将详细的讲解这些属性的意义并论述它们如何使用;
8. 选择Window | Catalog或按CTRL-Y打开控件工具箱;
9. 拖动一个按钮至窗体的中心。现在按钮的属性将代替窗体的属性出现在窗体对话框的左边。这些属性缺省就可以了,以后将详细讨论它们。你如果十分渴望改变按钮的位置的话,你可以改变L eft Origin 和Top Origin属性;
10. 单击Label属性,将其名称由OK改为Hello;
11. 单击右侧的面板,重新得到窗体属性;
12. 选择Layout | Hide Object Ids。这将使你确实看到写有“Hello”的按钮。如果“Hello”看起来字体比较大,这是因为你遇到了我在安装部分讲到的古怪字体问题。为解决这个问题,关闭构造器,打开W indows文件夹中的Fonts文件夹,然后重新打开构造器。你的“Hello”窗体将如图2-5所示;
13. 选择Fiel | Save保存工程资源。将其保存在Hello工程文件夹的Src子文件夹下面。并命名为hello.rsrc。
14. 当你完成你的新工程后,下一步该涉及到总工程。资源工程是总工程的一部分,总工程将包括所有有关用户界面的图形描述的各个方面,例如:大小、布局及窗体和控件的外观等;
15. 再次打开Code Warrior集成开发环境,选择File | Open Recent | hello.mcp;
16. 选择Project | Add Files。置文件类型为“All Files”以便能看见的资源文件。找到hello.rsrc打开;
17. 这时资源文件会出现在工程的顶部。为简洁起见,把它拖到应用程序(AppResource)资源组的下边。为此,你可以按住鼠标把文件图标拖到应用程序(A ppResource)资源组的下部,当出现在资源组下面出现一直线时,松开鼠标;
18. 到此为止,你已成功的创建和添加了新的资源。
生成代码
为使你的程序能够运行,必须添加C代码,步骤如下:
1. 建立可以写入代码的新文件,你可以选择File | New Text File创建之;
2. 选择File | Save As保存文件为hello.c;
3. 选择Project窗口,选中Project | Add Files。找到hello.c添加之;
4. 如果它不在AppSource文件夹,可把它拖到该文件夹中。当你拖动文件的时候,你会发现一条直线,它允许你把文件插入;
将下面的代码输入到hello.c文件中。在下一部分将逐行进行详细的讲解。
/* The super-include for Palm OS */
#include
/* Our resource file */
#include "hello_res.h"
/* A prototype for our form handler function */
static Boolean myHandleEvent( EventType* event );
/* The main entry point */
DWord PilotMain( Word cmd, Ptr, Word )
{
FormPtr form; /* A pointer to our form structure */
EventType event; /* Our event structure */
/* If this is not a normal launch, don't launch */
if( cmd != sysAppLaunchCmdNormalLaunch )
return( 0 );
/* Initialize our form */
form = FrmInitForm( HelloForm );
FrmSetEventHandler( form, myHandleEvent );
FrmSetActiveForm( form );
FrmDrawForm( form );
/* Our event loop */
do
{
/* Get the next event */
EvtGetEvent( &event, -1 );
/* Handle system events */
if( SysHandleEvent( &event ) )
continue;
/* Handle form events */
FrmDispatchEvent( &event );
/* If it's a stop event, exit */
} while( event.eType != appStopEvent );
/* We're done */
return( 0 );
}
/* Our form handler function */
static Boolean myHandleEvent( EventType* event )
{
/* Parse the event */
if( event->eType == ctlSelectEvent )
SndPlaySystemSound( sndAlarm );
/* We're done */
return( false );
}
代码分析
源代码由两个函数组成。它创建了一个窗体和可以退出应用程序的按钮。当然,在程序为解决实际问题而变的更复杂时,我们必须增加更深层的程序结构。
下面是代码的逐行解释。
/* The super-include for Palm OS */
#include
Pilot.h包括了所有Palm OS相关的头文件。
/* Our resource file */
#include "hello_res.h"
深入(IN DEPTH)注意到Pilot.h包含在<>中而hello_res.h包含在引号中了吗?这就是说,编译器将在Palm OS所指定的系统文件夹中寻找Pilot.h,而对于hello_res.h,则先在Hello\Src中寻找,若找不到再到所有的文件夹中寻找。
当你创建hello.rsrc时,hello_res.h随之也建立了。hello_res.h中包含了窗体和控件的ID标识符常量。
注意:在运行之前,应把hello_res.h添加到你的工程中,它允许你方便的查看和编辑。添加文件时,首先选择Project | Add Files。找到hello_res.h将之拖到AppSource文件夹中。
/* A prototype for our form handler function */
static Boolean myHandleEvent( EventType* event );
以上就是处理窗体事件和控件事件的回调函数的原型,所谓回调函数就是在应用程序中的一个系统调用,它一般用来响应系统或用户自定义的事件,譬如你用输入笔点击窗体中的按钮所产生的事件。
函数PilotMain()
/* The main entry point */
DWord PilotMain( Word cmd, Ptr, Word )
{
PilotMain()就是包含了被称为启动代码的函数。变量cmd 提供了激活应用程序的入口。接下来我将告诉你开始运行启动代码后,其它参数将起到什么样的作用。
如下定义了指向窗体的指针。
FormPtr form; /* A pointer to our form structure */
如下定义了指向当前事件的指针。EventType是一个数据结构,包含了当前事件的所有信息。
EventType event; /* Our event structure */
小技巧:
一般我们会先查看一下PilotMain()函数头部是否存在一些识别Palm OS版本的代码,以确保程序在发现操作系统存在任何不兼容的现象后,安全而体面的退出。为了达到这个简单的目的,我先把这部分代码分离出来如下。需要事先说明的是,现在提供的这个应用程序确实能够运行在任何P alm 设备上,因为它只用到了很少的系统资源,但是在运行其它复杂的程序时就存在一些不可预料的问题了。让我们从下面的代码看起。
Dword ROMVersion;
//Get the ROM version
ROMVersion = 0;
FtrGet ( sysFtrCreator ,sysFtrNumROMVersion, &ROMVersion );
//Alert and bail if the ROM version is too low
if ( ROMVersion < ROM_VERSION_MIN )
{
// Do something here that reports an error
//Palm OS 1.0 will continuously re-launch this app
//unless we switch to another safe one
if ( ROMVersion < ROM_VERSION_2 )
{
AppLaunchWithCommand( sysFileCDefaultApp,
sysAppLaunchCmdNormalLaunch, NULL );
}
return ( 0 );
}
通过函数Ftret()的调用可以得到ROM中Palm OS的版本。从而得知当前运行的Palm OS版本是否达到了你应用程序的最低运行配置。一般Palm OS 1.0版本的处理方法是不停的重新加载应用程序(如果上一次加载不成功的话),直到你主动切换到其它的应用程序。这样就有可能使你陷入一种近乎死循环的尴尬局面,所以,在这样的情况发生前你应该先调用A ppLaunchWithCommand()函数,使你得以从容跳出当前的应用。
下面是环境检查代码,你可以藉此查验当前的运行环境是否是一个正常的运行环境(normal cicumstances)。到下一章,我们还将看到其它的运行环境。
/* If this is not a normal launch, don't launch */
if( cmd != sysAppLaunchCmdNormalLaunch )
return( 0 );
下面是一些关于Palm OS内嵌窗体管理器的函数调用。首先,调用FrmInitForm()函数,使我们的窗体进入备用状态。通过使用FrmSetEventHandler()函数为窗体绑定事件处理函数(e vent handling function)。然后,使用FrmSetActiveForm()函数来激活窗体。最后,调用FrmDrawForm()显示窗体。
/* Initialize our form */
form = FrmInitForm( HelloForm );
FrmSetEventHandler( form, myHandleEvent );
FrmSetActiveForm( form );
FrmDrawForm( form );
下面是事件循环的开始部分。
/* Our event loop */
do
{
深入: 什么是事件循环?事件循环是用来处理应用与用户,及应用之间交互的一种程序循环,譬如处理输入笔运动、按钮被按下等用户事件。许多现代图形用户界面(G UI),如Mac OS、Windows等都是事件驱动的操作系统。事件是一种操作系统和你的应用程序精确交互的手段,从而可以得知用户正在对应用程序做一些什么样的操作。一般,如P alm OS这样简单的操作系统,通常按发生的顺序来保存事件,用户可以请求事件和处理事件。
下面这个函数从ROM中调用事件处理器(Event Manager),并把老的事件放到队列中,以操作系统接收的先后顺序来处理事件。
/* Get the next event */
EvtGetEvent( &event, -1 );
下面的函数调用了系统管理器用来处理系统事件。
/* Handle system events */
if( SysHandleEvent( &event ) )
continue;
下面这个函数不但调用了回调函数处理事件,而且还执行了很多其它的任务。譬如,使用penUpEvent 和penDownEvent 两个原始事件来产生新的事件,这就像ctlSelectEvent事件,我们使用在窗体事件处理函数中去决定按钮是否被按下了。这就是我们使用系统回调函数处理事件而不是把所有事件都放到一个巨大的事件循环中去的原因。
/* Handle form events */
FrmDispatchEvent( &event );
一旦另一个应用程序被用户选择,就交由下面的代码来处理程序退出前的一切善后工作。 在这个例子程序中并没有什么需要清除的,所以我们就可以通过结束循环来退出执行中的应用程序。这些代码往往出现在循环的底部,因为我们在退出时总是需要往窗体事件处理器(或者其它的处理函数)中添点什么代码的,所以让这个退出事件接收循环贯穿整个程序结构是很有好处的。
/* If it's a stop event, exit */
} while( event.eType != appStopEvent );
/* We're done */
return( 0 );
}
helloHandleEvent() 函数
还记得吗?我们调用FrmSetEventHandler()函数的时候就是通过传递helloHandleEvent()函数的入口地址给Palm OS来实现的。这个函数通过调用FrmDispatchEvent()函数来处理窗体事件。
/* Our form handler function */
static Boolean myHandleEvent( EventType* event )
{
这个事件发生在窗体上的”Hello”按钮被按下后,在例子中,我同时让系统发出了警报音。
/* Parse the event */
if( event->eType == ctlSelectEvent )
SndPlaySystemSound( sndAlarm );
/* We're done */
return( false );
}
我的编程风格是通过超过500,000行以上代码,16年的程序生涯养成的。然而,看了我的程序并不意味着就学到了我的风格。我认为,不应该全部照搬书中的内容,而是要采用自己的方法来编程,并且不为尝试自己独特的编程风格而感到惭愧不安。用自己的方法写自己的样列程序,往往能使人更好的学习和理解那些内在的原理,所以我是非常赞同程序员编写自己风格的代码的。
调试:使它工作起来
在这一部分你就可以开始编译和链接这个项目工程了。首先选择运行Project | Make。如果你像我那样干的话,就可能会搞出一些BUG的(当然了并不是所有的方面都是完美的嘛)。祝你们好运吧。
Okay, Okay,我们已经取得不少的进步了。你现在可以通过Compare files操作比较快速的除掉一些编译时间错误了。如果你在创建工程的时候意外的删除了库文件,那么就会产生连接错误。你最好的处理办法就是尽早做好这些文件的备份工作。
发现运行时间错误的最好方法就是逐行的调试程序。你可以在Code Warrior IDE集成环境中执行下面的一些调试步骤:
1.在PC上选择Project | Debug 或者 点击F5来编译和连接工程,然后调出调试器(debugger)。
2.在Palm上,把设备先置位到Console模式。最简单的方法就是利用find框,删除find输入框中原有的文字并输入快捷符号。快捷符号很像连写的小写字母“l ”,你在输入区上画一个连写的“l”以产生快捷符号。然后写一个句号(在输入区轻击两下)和数字“2”。在你这样做后,你会发现Pa lm设备会发出声音并且所画的内容将消失。图2-2显示了把Palm设备设置为Console模式所要画的图形;
3.在PC上,点击OK用来下载应用程序到Palm设备。再点击OK,来去掉Palm上出现的Code Warrior lite警告框,现在你就应该停在Code Warrior 调试器中,PilotMain()函数的第一行了。
4.在PC上,点击调试器窗口顶端看起来象一个向右箭头的按钮。这将使你以单步调试的方式运行程序,进入函数后,箭头每次都将停留在下一步将要执行的语句上。点击另一个像向上箭头的按钮,将使你跳出任何一个执行中的函数。
5.在PC上,按下调试器窗口顶端的“X”按钮可以重置Palm设备。如果你的Palm设备已经关掉,那就再打开,然后按下“X”按钮,则设备将被置于一种良好的C onsole模式关闭的状态。当然,也可以通过使用图钉或其它尖的东西按下Palm背面的Reset按钮,来达到同样的目的。
值得庆幸的是,我早期的一些源代码评论将对你有用,特别是像你这样正努力推测程序中每条代码含义的时候。当然,如果你的窗体根本不显示的话,那么你就得首先确保你已经正确连接了当前资源文件(* .rsrc),以及通过在FrmDrawForm()函数入口设置断点和单步跟踪来确保它是否被调用了。
你也可以通过点击每行左边的页空白处来设置断点。如果设置了断点,一个小红点将出现在该行左边的页空白处。去掉断点只要点击该行左边页空白处显示的小红点就可以了。
图2-6显示了本示例程序运行的样子
图2-6显示了本示例程序运行的样子
当你的Hello示例程序被完全调试好之后,你将会发现:
1 在Palm的应用程序区将出现“Hello”的图标
2 一旦程序被加载,将显示它的窗体和“Hello”按钮
3 当“Hello”按钮被按下,程序将退出
4 当按下Palm上的4个真正的按钮或任何一个输入板(graffiti pad)边上的“Silkscreen bottom”,程序都将退出
祝贺你。你已经写完了你的第一个Palm OS 应用程序了。这是一个很好的程序,可以用来测试你当前使用的代码中是否存在一些不易发现的不安全的设置。
当你运行你的程序时发生了什么?
现在你已经拥有一个能工作的Palm OS程序了,让我们设置一个断点,再一次单步调试,以便于更加深入的了解它是如何工作的。
1.在PC上,开始运行调试器。选择Project | Debug 或 按下 F5 开始编译和连接工程以及弹出调试器。
2.在Palm上,设置你的设备到Console状态。使用find框,删除find输入框中原有的文字并输入快捷符号。快捷符号很像连写的小写字母“l ”,你在输入区上画一个连写的“l”以产生快捷符号。然后写一个句号(在输入区轻击两下)和数字“2”。在你这样做后,你会发现Pa lm设备会发出声音并且所画的内容将消失。图2-2显示了把Palm设备设置为Console模式所要画的图形;
3.在PC上,单击OK后,下载应用程序到Palm。现在你需要在PilotMain()函数的第一行设置断点。
4.在PC上,从调试器窗口中找到,如下代码:
/* Parse the event */
if( event->eType == ctlSelectEvent )
SndPlaySystemSound( sndAlarm );
5.在PC上,在if语句前设置断点。
6.通过反复的按下执行一行代码的按钮,来单步逐行调试整个程序。注意到,FrmDispatchEvent()函数的调用经常停留在窗体事件处理器上(m yHandleEvent()),但由于发生的并不是ctlSelectEvent,所以SndPlaySystemSound()就没有运行。跳过SndPlaySystemSound()函数后,程序又进入了G etEvent()状态,等待其它事件的发生了。
7.点击Palm上的“Hello”按钮,注意到,GetEvent()函数响应了,窗体事件处理器被反复调用了许多次,这次终于发生了ctlSelectEve nt,于是SndPlaySystemSound()就被调用了。你现在已经亲眼目睹了你的代码分配和处理一些事件的全过程了。
8.在PC上,按下调试器窗口顶端的“X”按钮可以重置Palm设备。如果你的Palm设备已经关掉,那就再打开,然后按下“X”按钮,则设备将被置于一种良好的C onsole模式关闭的状态。当然,也可以通过使用图钉或其它尖的东西按下Palm背面的Reset按钮,来达到同样的目的。
把你的工程存放到固定的目录中
在第四章中,我们将使用本章做好的应用程序作为整个程序外观的基础。在Code Warrior中,提供了一种叫做“Stationary”的建立详细工程项目的模板,现在就请把当前项目做成一个模板。在你的 Code Warrior下的Stationary子目录中保存一个应用程序模板的拷贝,这样当你下一次选择New Project选项的时候它就会出现。你也可以按照以下步骤在Windows资源管理器中复制应用程序模板:
1.打开Windows资源管理器,找到你的Hello工程的目录。
2.选中整个Hello工程目录。
3.按下CTRL-C复制目录
4.在Code Warrior目录下找到Stationary子目录,进入。
5.按下CTRL-V复制Hello目录。
接下来讲什么?
在下一章中,我们将开始研究文本框,用以输入文本。