如何维护用于 Pocket PC 和 Smartphone

概述
为了使应用程序的维护和支持工作尽可能少,应该尽可能使您计划支持的平台都用统一的源代码。按照以下技巧,您甚至可以使一个二进制文件在两个平台上都能运行。如果您的目标是所有版本的 Pocket PC 和 Smartphone,那么使大多数业务逻辑代码保持同步是相对简单的方式,因为所有 Pocket PC 和 Smartphone 版本都是基于 Microsoft® Windows® CE 的。新版本的 Pocket PC 2003 和 Smartphone 2003 使用 Windows CE 4.2,并且需要 eMbedded Visual Tools 4.0 (eVT 4.0)。而旧的设备仍然使用 eMbedded Visual Tools 3.0 (eVT 3.0)。

关键代码技巧
为平台执行运行时检查

许多开发人员都是检查屏幕分辨率,然后使用该信息来确定承载应用程序的是什么平台。市场上有几种工具可以更改 Pocket PC 的屏幕分辨率(例如,Nydidot 的 Virtual Display 或 Jimmysoft 的 JS Landscape)。检测平台的正确方式是:

#define POCKETPCV1   1
#define SMARTPHONEV1   2
#define POCKETPCV2   3
#define SMARTPHONEV2   4
int MyDeviceType()
{
TCHAR szPlatform[MAX_STRING_BUFFER];
int iDeviceType=0;
   OSVERSIONINFO osVer;
   GetVersionEx(&osVer);
   if (osVer.dwMajorVersion==3)
{
if (SystemParametersInfo(SPI_GETPLATFORMTYPE,
sizeof(szPlatform),szPlatform,0)!=0)
      {
if (lstrcmp(szPlatform,TEXT("PocketPC"))==0)
                  iDeviceType= POCKETPCV1; // runs on Pocket PC 2000 and 2002
            else if (lstrcmp(szPlatform,TEXT("Smartphone"))==0)
                  iDeviceType= SMARTPHONEV1; // runs on Smartphone 2002
}  
else
{
   if (GetLastError()==ERROR_ACCESS_DENIED)   //(5)
      iDeviceType= SMARTPHONEV1;      // is a smartphone:
      // Smartphone creates an access denied error on
      // SystemParametersInfo()
}
}
else
{
      if (osVer.dwMajorVersion==4)
   {
   if (SystemParametersInfo(SPI_GETPLATFORMTYPE,
sizeof(szPlatform),szPlatform,0)!=0)
           {
if (lstrcmp(szPlatform,TEXT("PocketPC"))==0)
                  iDeviceType= POCKETPCV2;      // runs on Pocket PC 2003
            else if (lstrcmp(szPlatform,TEXT("Smartphone"))==0)
                  iDeviceType= SMARTPHONEV2;      // runs on Smartphone 2003
   }  
   else
   {
      if (GetLastError()==ERROR_ACCESS_DENIED) //(5)
         iDeviceType= SMARTPHONEV2;         // is a smartphone:
         // Smartphone creates an access denied error on
         // SystemParametersInfo()
   }
}
}
return iDeviceType;
}在 Smartphone 上,调用“SystemParametersInfo()”可能会因“Access Denied”而失败,这取决于 Smartphone 是否锁定和应用程序签署的证书。因为只有这种平台才会因 Access Denied 而调用失败,所以您也可以用它作为 Smartphone 的标记。

检查屏幕分辨率

虽然我描述了应该如何检查平台而不是通过检查屏幕分辨率来检测平台类型,但是一旦知道了平台,您还需要知道设备的屏幕分辨率。再次强调,不要假设 Pocket PC 或 Smartphone 有任何固定的分辨率。Windows Mobile 今后版本将支持不同的屏幕分辨率和方向。

一旦知道了屏幕分辨率,您就可以调整窗口来适合它。如果您的应用程序基于对话框,您必须为想要支持的每种分辨率创建独立的对话框资源,或手动将控件放在对话框中。不管哪种情况,您都应该将控件放在 WM_SIZE 处理程序中。

最小化菜单项

尝试将菜单限制为两个主菜单,而且最多七个子菜单。

Smartphone 有两个热键,对应于两个屏幕菜单。对于 Pocket PC,我建议也不要为了改进用户界面设计而超过这一限制。另外,避免使用级联菜单。Smartphone 不支持这个功能,它会使大多数 Pocket PC 用户不知所措。

将通用对话框的使用限制在最低限度

Smartphone 不支持通用对话框。如果您需要保存文件,要么请求名称,要么自动生成某些描述名称,然后将它保存到“My Documents”。当您想要检索文件时,请将应用程序可以加载的所有文件填充到一个微调控件中,让用户从中选择一个文件。

Pocket PC 不支持用于保存和加载的通用对话框,但您应该为 Pocket PC 考虑相同的方法,这样不仅更方便于使用,也可以使代码保持同步。如果您的应用程序需要“Save File”或“Load File”对话框,您就应该在 Pocket PC 中使用通用对话框。

只保存到“My Documents”并从中加载

Pocket PC 和 Smartphone 是为那些还不想在旅途中管理存储区的用户构建的。如果您必须将某些东西保存到存储媒体或者从中加载,请使用“My Documents”文件夹来存储数据。当在设备中插入存储卡时,可能又会产生一个问题,需要询问用户:“是否存储到存储卡中?”。

下面是一小段代码,它告诉您如何发现存储卡:

void ShowFlashCard()
{
BOOL bContinue = TRUE;         
HANDLE hFlashCard;             
WIN32_FIND_DATA lpwfdFlashCard;   
   hFlashCard = FindFirstFlashCard (&lpwfdFlashCard);
   if (hFlashCard == INVALID_HANDLE_VALUE)
      return;
   while (bContinue)
   {
      MessageBox(NULL,lpwfdFlashCard.cFileName,
                       TEXT("FindFlash"),MB_OK);
      bContinue = FindNextFlashCard (hFlashCard,
                                           &lpwfdFlashCard);
   }
   FindClose (hFlashCard);  // Close the search handle.
}在 Smartphone 中,My Documents 文件夹不在根目录中。如果您硬编码为“/My Documents”,则应用程序不会存储到 Smartphone 的持久位置中。德语版的 Pocket PC 的这个目录名称为“/Meine Dokumente”,这样的调用也会失败。相反,应该使用以下的调用来获取指向“My Documents”的正确路径。

SHGetSpecialFolderPath(NULL,szTxt,CSIDL_PERSONAL,0);CSIDL_PERSONAL 请求“My Documents”文件夹以 szTxt (TCHAR) 形式返回。

为每个平台创建资源或者使用“condition”属性

如果您想让相同的二进制文件既可用于 Pocket PC,又可用于 Smartphone,您必须创建两种资源定义,一个平台一种。如果您只想使源代码保持同步,您可以使用资源的“condition”属性来包含正确的资源。

假如您想让二进制文件具有兼容性,您需要在代码中加载 Pocket PC 或 Smartphone 资源:

switch (iDeviceType)   // Determined with tip -1- above
      {
         case SMARTPHONEV1:
         case SMARTPHONEV2:
               idd=IDD_SMARTPHONE;
            break;
         case POCKETPCV1:
         case POCKETPCV2:
               idd=IDD_POCKETPC;
            break;
         default:
               idd=IDD_HPC;
            break;
      }
      return DialogBox(hInst,MAKEINTRESOURCE(idd),
                     hWndMain,(DLGPROC)StartDlgMain);如果您使用资源的 Condition 属性,请在 condition 字段中放入“WIN32_PLATFORM_WFSP”(对于 Smartphone)和“WIN32_PLATFORM_PSPC”(对于 Pocket PC)。请记住 Palm-size PC(Pocket PC 的前身)和最近出现的 Pocket PC 2003 与 Smartphone 有相同的定义,所以如果您想加以区分,您需要创建自己的定义。如果您试图保持二进制文件/可执行文件的平台无关性,您必须对不同平台使用不同资源,但将二者都包含在资源文件中。

动态加载 Pocket PC 和 Smartphone 的特定库

您可以看到,这是有助于开发的最重要的技巧。任何时候加载以下 DLL 的其中一个时,请确保使用“LoadLibrary”和“GetProcAddress”,而不是将 DLL 静态链接到应用程序:

AYGSHELL.DLL (AYGSHELL.LIB/AYGSHELL.h)。包含所有 SIP、SH… 和其他特定于 Pocket PC 的函数。该 DLL 也可用于 Smartphone,但有不同的功能集。

CELLCORE.DLL (CellCore.LIB/TSP.h and others)。这个 DLL 只存在于 Pocket PC 2002 Phone Edition 和 Smartphone,而不存在于 Pocket PC 2000。它包含了用于连接管理器和进行电话呼叫的所有函数。

在运行时加载这些 DLL 可以让您开发一些智能的错误处理,它仍然允许应用程序在不具备这些库所提供的功能的情况下运行。如果这些库在编译过程中静态链接,则在 Pocket PC 2002 上应用程序甚至不会启动,因为它试图加载这些 DLL 并给出错误“One or more components are missing”。

如果您只想使源代码保持同步,您不需要这样做;而可以将这些库链接到编译过程中。然而要注意,每次在 Pocket PC 2000 和 Pocket PC 2002 编译过程间切换时,都必须手动取出 cellcore.lib。

不要假设有触摸屏

Smartphone 没有触摸屏,而 Pocket PC 没有数字键可以点击,但这两种设备都支持 D-pad 的类似于键盘的导航。因此,如果您想保持源代码同步,所有需要导航的用户输入都应该通过 D-pad 导航来实现。Pocket PC 中的菜单是通过触摸屏激活的,而在 Smartphone 中是通过热键激活的。但因为平台会为您处理该输入,所以您不需要为此担心。

小结
虽然保持代码同步需要做的相对较少,但只维护一种源代码所带来的好处是巨大的。大多数问题都是因为屏幕大小和输入方法的不同引起的。如果您遵循以上的技巧,您就能够编写出很酷的跨平台应用程序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值