为Windows CE编程
DEVEN - PDASKY - 2003-4-16
Windows CE是第三代Windows。这种新的操作系统不如它的两个兄弟Windows 98和Windows NT那样出名,但是这种状况正开始转变。Windows CE是为小型的、由电池供电的设备而设计的,这些设备看起来与桌面和膝上PC机相当不同,但是为Windows CE设备编程的技术与基于Windows的PC机非常相似。我们将讲述如何为Windows CE设备编程,但首先应该理解什么是Windows CE。
Windows CE是一个全新的Windows版本。它不是一个被修改过的或拆开过的Windows 98或Windows NT版本,相反,Windows CE由Windows 98或NT设计而来,专用于由电池供电的比标准PC机小的设备。用户可能对Windows CE设备(如手持电脑和掌上电脑)比对这个操作系统本身更加熟悉。这些设备在它们的ROM中事先写入了Windows CE的某个版本,由于这个原因,用户从不需要自己安装Windows CE。
Windows CE支持Windows 98和Windows NT中普遍使用的Win32 API的子集。虽然子集这个单词可能会让许多Windows NT开发人员寒心,但其余的部分保证Windows的桌面版本和Windows CE之间API的差异不会导致太多编程上的挑战。两者之间的差异主要表现在消除了存在于Win32 API中为向后兼容Windows的先前版本而保留的冗余函数。例如,在Windows的桌面版本中通过编程打开一个文件可能需要三步或四步,而在Windows CE下,只需要一步,那就是CreateFile。
API的其他差异还在于Windows CE没有实现Windows NT支持的全部函数数组,例如,Windows CE支持的Winsock库不包括Windows 98和NT支持的大部分WSAAsync函数。在Windows CE版本中,并没有损失任何功能,当在Windows CE下使用socket时,你就不得不使用更多的纯Berkeley版本的socket编程。对Windows 程序员,这意味着在没有WSAAsync函数的情况下,你需要学会怎样使用基本的阻塞和非阻塞socket以通知应用程序socket事件发生。
在Windows CE和它的兄弟之间的其他主要区别是Windows CE的设计能够让OEM重新配置以便更好地适应特定的硬件平台。例如,对手持电脑(运行Windows CE的袖珍型笔记本)专业人员的要求与对掌上电脑人员的要求就大不相同。因为这个原因,Windows CE能够被配置,以便达到某种目的,例如,控制屏幕上指针外形的光标API或者剪贴板组件在被认为对特定硬件平台不是必需的情况下能够被移去。
Windows CE的构成由市场纵向的OEM或者是横向的Microsoft决定。一个特殊成分生成一个用于Windows CE配置的特定的API,因此,用于Casio H/PC的API与用于NEC H/PC的API是一样的,因为两个系统都使用Microsoft为H/PC设备指定的Windows CE的同一种配置。另一方面,在用于H/PC的API之间存在一些细微的差别,这是因为在这两种平台之间Windows CE的特殊组件不同。然而,这些差别不应该被过分夸大。即使你不钻研某个平台上支持的特定API,你也不会遇到编写运行在这两种平台上的应用程序的任何麻烦。通常你可以通过使用LoadLibrary和GetProcAddress显示链接到特定平台的函数来避免这类问题。
实际上,编写运行在两种不同平台之上的应用程序的最大挑战是处理这两个平台所使用的不同屏幕尺寸。例如,H/PC的屏幕(640×240)需要一个与掌上电脑的屏幕(240×320)不同的对话框布局。在本例中一个比较好的解决方法是为两种屏幕尺寸创建带有不同的对话框模板的单独的对话框过程。在运行时,应用程序能够确定使用正确的模板。
编写Windows CE设备的另一个挑战是你的应用程序必须生存在少量的内存环境中。尽管Windows CE支持内存分页,但是它不支持页面文件以保存辅助设备(如硬盘)的读/写型数据。换句话说,只读页面,如应用程序代码和应用程序的只读数据应尽可能地载入内存。然而,读/写型数据从不被保存在硬盘上的分页文件中。这种分页的限制减少了启动Windows CE应用程序所耗费的时间,因为在启动时仅仅是应用程序的必需部分被载入。但是它还意味着因为Windows CE不支持分页文件来保存读/写型数据,所以应用程序严格地受限于设备上物理RAM的数量。由于这个原因,应用程序经常出现内存不足是相当可能的事情。因此,你必须编写出尽可能少使用RAM和能够正确处理内存不足状态的应用程序。
工具包
Windows CE的灵活性给编写编程工具的人们提出了一个挑战。因为Windows CE支持各种CPU和能够以多种方式被配置,每种方式带有一个不同的API,开发环境怎样才能知道目标平台呢?为了解决这个问题,Micrsoft已经开发了一组Windows CE开发工具,某些兼容所有的平台,某些仅支持手持电脑和其他专门的系统。
这个工具包可以运行在Windows NT下,用下面提到的任何一种可支持的语言在Developer Studio中进行代码开发。你可以使用串行连接或网络连接将Windows CE连接到开发用的PC机上,代码在Windows CE上执行。串行连接是Windows CE设备使用的用来在设备和PC之间同步数据的标准连接。网络连接提供了快得多的下载速度,但不幸的是,当通过网络连接到Windows CE设备时,某些调试工具不能够运行。
Visual C++、Visual Basic和Visual J++的任何版本都可用于一个或多个Windows CE平台。用于Windows CE的Visual Basic和Visual J++仅支持手持电脑和手持电脑专业系统。目前,要为其他平台编写应用程序,你必须使用Visual C++,它支持跨平台编程。尽管你可能想在手持电脑和手持电脑专业系统中使用其他语言为Windows CE编程,我们仍然将讨论局限在Visual C++上。
要用C或C++编写Windows CE应用程序,你首先应该安装Visual C++ (VC++ 5.0或6.0)的标准PC版本,然后安装附加产品—Visual C++ for Windows CE。该产品提供对所有Windows CE目标CPU的支持,并且包括了H/PC上支持的MFC和ATL版本。附加产品并不能禁止你编写用于PC的应用程序,它只是简单地扩展了目标以便你能够为Windows CE进行开发。
同时,你还需要include和lib文件来为特殊的平台编译Windows CE应用程序,如果你正在为标准的纵向平台编写应用程序,那么下一步是安装用于特定平台的SDK。这些SDK可以从Microsoft免费获得,也可以从Microsoft Web站点(http://www.microsoft.com/windowsce/downloads/pccompanions/default.asp
)下载。当你购买Visual C++ for Windows CE后,用于H/PC平台的SDK通常包含在CD中,但是应该经常检查Web站点,以确定是否可获得更新的版本。
如果要将Windows CE转向一个新的硬件平台,那么Microsoft提供了另一个工具—Windows CE Platform Builder,它是与Windows CE的先前版本一起使用的内嵌式工具包的后继产品。该工具以对象库格式提供给操作系统,以便开发人员可以将其作为特定操作系统平台的组件。Platform Builder还包括一些必需的工具,以便开发人员可以为组件化的操作系统版本创建特定平台的SDK。
尽管对正在为H/PC或其他横向平台编写应用程序的软件开发人员来说并不真正需要使用Platform Builder,但是如果你对Windows CE开发十分投入,那么拥有Platform Builder肯定值得。这是一个复杂的工具集,但是通过使用Platform Builder所获得关于Windows CE结构的信息是没有什么价值的。以后我们将更多地讨论Platform Builder。
基本开发周期
现在让我们转向编写一个实际的Windows CE应用程序。你要采取的步骤与编写Windows桌面版本应用程序的步骤相同。首先,在Visual C++中创建一个新的工作区。尽管可以使用向导来帮助你创建Windows CE应用程序,但你也可以通过选择Win32应用程序和核对你想要的Windows CE目标处理器手工创建一个应用程序。
一旦创建了工程,你只需简单地编写代码和创建任何资源,包括菜单、图标和对话框模板,这几乎与你为Windows 98或Windows NT编程完全一样。正如我前面所提到的,尽管差别不是十分大,我们也应该注意到在Windows CE编程模型中的一些特殊之处。首先,Windows CE下的顶层窗口不支持菜单。这并不意味着Windows CE应用程序不能拥有菜单,只不过是通过命令条控件来支持它们。
命令条控件和更复杂的同类控件—命令带控件—结合了对菜单和工具条的支持以及关闭应用程序按钮和帮助按钮。这些控件的设计使编程十分直截了当。实际上,一个简单的提供了菜单和关闭应用程序按钮的命令条只需编写三行代码。命令带控件允许命令条、菜单、按钮和其他控件被分割为单独的带,从而拓展了命令条概念。这些带能够被用户重新排列。命令带控件基于为Internet Explorer 3开发的rebar控件。
与Windows NT应用程序另一个不同之处是:图标根据应用程序中的类而不是根据窗口实例来分配,也就是同一窗口类的两个窗口共享相同的图标。因为一个窗口图标仅在代表窗口的任务按钮中显示,所以这毫无影响。
除上述问题之外,其他的不同点多数在于编程约定,而不是编程限制或编程实现。例如,尽管Windows CE顶层窗口能够拥有标题栏,但是通常它们并不具有标题栏。移去标题栏节省了Windows CE设备使用的小屏幕的空间。在Windows的桌面版本上,标题栏用来在屏幕四周拖动窗口。在Windows CE系统中不常使用该函数,因为Windows CE中的顶层窗口是满屏的。
从Windows CE 2.1开始,窗口管理器支持标准的、大小可变的窗口。尽管操作系统一直支持任何固定尺寸的窗口,但是现在窗口管理器支持在重叠窗口四周的可变边框以便用户改变窗口大小。然而对顶层窗口来说,由于缺省情况下是全屏,所以在新的H/PC Pro机器上你将不会经常看到可改变大小的窗口。
让我们观察一个简单的Windows CE应用程序。图1显示了简单的TinyCE应用程序的源代码,TinyCE应用程序仅在它的主窗口中显示一行文本。乍看之下,Win32编程人员不得不注意该应用程序和Windows 98或NT应用程序之间细微的差别。该程序与其他窗口应用程序一样拥有相同的窗口类注册、窗口创建、消息循环和窗口过程。示例中的不同之处反映了上面所讨论的在API中的差异,如使用命令条来提供关闭按钮。一旦编写好代码,你可以使用与你处理桌面应用程序完全相同的技术来编译和运行应用程序。编译结果不包括将编译结果EXE或DLL自动下载到所连接的Windows CE设备上的额外步骤。你能够通过选择程序|运行菜单项在Windows CE设备上运行应用程序,它与你在开发环境下运行Windows NT应用程序一样。
你可以使用集成的调试器来一步一步地执行应用程序。调试Windows CE应用程序和调试本地Windows NT应用程序的主要不同之处在于,运行速度会受开发用的PC和远程Windows CE系统之间串行连接速度的影响。此连接使单步调试成为一个缓慢的、令人痛苦的过程。实际上,我们一般仅在解决最难处理的bug时使用调试器。
有两种使用远程调试器的方案可供选择。用于H/PC平台的SDK、掌上电脑和车载电脑都包含模拟器应用程序,它们试图在Windows NT上模拟Windows CE设备。此模拟器运行一个应用程序临时编译过的版本,它模拟Windows CE API,其中包括扩展的API(如数据库API)。模拟器的问题在于它不能完美地模拟Windows CE环境。在一天的工作之后,当你意识到你正在捕获的问题是模拟器的问题,而不是代码中的bug时,它可能已经出现数次了。
创建自己的Windows CE应用程序是一个不错的主意,它能够被编译成既可以用于Windows CE,又可以用于Windows NT的应用程序,于是可以避免模拟器问题。该方法让你在Windows NT下对应用程序的不同部分进行工作,同时又让你简单地通过选择不同的目标,编译用于Windows CE的应用程序。但是如果你这样做,请注意不要在其中一种平台上工作太久。如果你花费太多的时间用来编译用于Windows NT的应用程序,那么修改应用程序以便它在Windows CE下运行可能需要花费一些精力。
编写既可以用于Windows NT又可以用于Windows CE的代码并不十分困难。对那些特定于操作系统的代码部分来说,可以使用编译器定义对这些段落有选择地进行编译,以用于特殊的操作系统。在下面的代码片段中,创建命令条的函数封装在#条件编译语句中,于是仅当编译用于Windows CE的应用程序时,它们才会被包含。
#ifdef _WIN32_WCE //如果编译用于CE
HWND hwndCB;
//创建命令条
hwndCB = CommandBar_Create (hInst, hWnd, IDC_CMDBAR);
// 将退出按钮添加到命令条
CommandBar_AddAdornments (hwndCB, 0, 0);
#endif //_WIN32_WCE
当然,编写代码仅是应用程序开发的一部分。你还需要一组工具来调试和测试应用程序。当你安装Visual C++ for Windows CE时,将会安装一组远程工具来帮助你调试Windows CE应用程序。这些工具与用于桌面Windows调试的工具有很大程度的相似性。这些工具中有Windows CE版本的Regedit,它用于编辑Windows CE设备上的注册表;Spy用来监视Windows CE窗口接收的消息;ZoomIn用来检查窗口像素。你还可以获取进程监视器,它让你观察和监视运行在设备上的进程的状态。状态信息包括在每个进程中运行的当前线程以及进程载入的DLL。最后一种工具是内存观察应用程序,它让你浏览应用程序堆的内容。所有这些工具运行在相连的桌面PC上并且与Windows CE设备上的远程客户软件进行通讯。
Platform Builder
开发用于Windows CE的应用程序仅仅是开发操作系统的一个机会。当桌面版本的Windows可能转向不同的PC兼容机时,可以实现这个目标的工具牢牢地掌握在Microsoft和它许可的OEM手中。但Windows CE的不同之处在于Platform Builder工具可以通过零售渠道购得。于是,Windows CE编程人员不仅能够开发应用程序,还能够开发操作系统自身的修订版本。
Platform Builder工具包提供了示例的用于OEM抽象层(OAL)的源代码,OAL是由OEM编写的用来使Windows CE适合特殊硬件的代码层。OAL包括硬件抽象层(HAL)代码,它用来支持Windows CE核心的需要以及支持内置硬件(如键盘、触摸屏和显示器)的驱动程序。它还提供了用于声音串行驱动程序以及PCMCIA控制器驱动程序的示例源代码。
Platform Builder还包含底层调试工具。虽然这些工具的设计目标主要是用来帮助将Windows CE转向新的硬件平台,但你还能够在分析应用程序软件所带来的难题时使用它们。更新版本的Windows CE提供了钩子来支持内嵌的Monte Carlo配置文件,它十分易于优化你的应用程序的性能。最后,Platform Builder包含了从OEM角度看关于Windows CE操作的扩展文档。
Windows CE是一个令人感兴趣的编程环境。Win32 API使它与Windows 98或NT编程非常相似,但是把硬件的限制强加在了应用程序的设计上。速度慢的CPU和多数Windows CE设备的有限内存使你不得不从效率的角度用不同的方式编程。实际上,在今天几兆字节的PC应用程序中看到程序人员不得不担心CPU速度和代码大小令人感到几分新鲜。