登录   注册智谷联账户
服务电话
主页 >> 支持服务
技术支持
产品相关问题解答
日常问题解答
产品升级方法
开发文档
Android开发
商务联系
周 强 先生
潘春桥 先生
刘 勇 先生
汪 伟 先生
杨 华 小姐
胡春维小姐
杨小霞 小姐
谭 群 小姐
周 刚 先生
无线点菜机
技术支持
谭 敏 小姐
智谷电wince产品应用程序可以选择哪些语言进行开发
   我要提问
智谷电wince产品应用程序可以选择哪些语言进行开发

目前有三个选项可供针对 Microsoft_ Windows_ CE .NET 的应用程序开发人员选择。它们分别是 Win32、Microsoft 基础类(以及 ATL,它主要用于创建 COM 组件、Web 服务和 Microsoft? ActiveX? 控件)和 Microsoft_ .NET 框架压缩版。这三种选择各有优势。作为应用程序开发人员,您需要决定使用哪一种选择来构建您的应用程序。

选择的过程中可能需要考虑多方面的因素。本文将着重讨论最重要的三个因素:应用程序文件的大小、运行时占用的内存以及快速应用程序开发。其他要考虑的因素可能包括安全性、健壮性、工作集需要、实时支持、性能、现有代码库等。我们将通过开发一个类似于 Scribble 的应用程序来考查各个运行时的开发过程。

如果您想知道运行时的相对大小,可以参考下表列出的各运行时的总体大小:

  • Win32。Win32 是操作系统的 API,因此编写 Win32 本机代码的应用程序时不需要考虑大小。利用 Win32 API 开发应用程序很耗时,因为这种编程方式利用的是操作系统最底层的 API(随后详细讨论)。

  • Microsoft 基础类 (MFC)。Windows CE 的 Microsoft 基础类是由两个 DLL 提供的:MFCCE400.DLL(大约 300 KB)和 OLECE400.DLL(大约 200 KB)。您的映像可能不需要 OLECE400.DLL,因此,最小的大小约为 300 KB,而总大小(包括 OLE [COM] 支持)约为 500 KB。请注意,Windows CE 不支持为桌面定义的 OLE(例如,将 Microsoft? Excel 电子表格嵌入到 Microsoft? Word 文档中)。我们确实支持“O”(在 COM 对象中,“O”代表“Objects”,即对象),但不支持链接和嵌入。

  • 框架压缩版。框架压缩版由许多 DLL 组成,例如 System.drawing.dll。框架压缩版的大小约为 1.3 MB。所有 Windows CE .NET 4.1 处理器都受支持。框架压缩版支持桌面 Microsoft? .NET 框架的一个子集。这并不奇怪,因为桌面框架的大小在 30 MB 以上。我们将在讨论应用程序时深入探讨这个话题。

为了说明包括 MFC 和框架压缩版时的大小差异,我为 Windows CE .NET Emulator 构建了一个“Internet Appliance”平台。下面是发布版本的大小比较。

运行时

大小(字节)

基本 Win32 平台上增加的大小

Win32

9,805,231

0

MFC

10,234,415

429,184

Compact Framework

11,201,459

1,396,228

在平台中添加对 MFC 或框架压缩版的支持非常简单,只需右击 Platform Builder 目录中的组件,然后单击 Add to Platform 即可。如果您只关心操作系统的大小,那么可以跳到本文的结尾,看看我们下个月要讨论的话题。对大多数读者来说,有关运行时的决策并非易事。

为了帮助您了解每个运行时涉及的工作量,下面我们分别用 Win32、MFC 和 .NET 框架压缩版编写一个 Scribble 式的应用程序(与 MFC Scribble 示例相似)。该应用程序将包括所有常用的功能(文件保存和恢复、菜单以及图形输出)。每个应用程序都需要处理同一组事件中的大多数事件:按下鼠标、移动鼠标、释放鼠标,以及构建一个可以在相应的画图/绘图功能中回放的鼠标点数组。它还需要处理文件的保存和恢复操作。听起来十分简单,对不对?好吧,现在我们打开一瓶 Jolt Cola,放松一下,然后开始编码。

Win32

为 Windows CE .NET 平台编写代码时,可以创建应用程序、驱动程序、控制面板小程序或 DLL。要创建某些底层代码,如设备驱动程序、实时代码、控制面板小程序等,本机 Win32 开发是唯一的选择。编写用户应用程序时,可以使用 Win32、MFC 或框架压缩版。在某些方面,您可能会考虑对某个设备进行分层,最底层为驱动程序和实时代码,它们用 Win32/本机代码编写;然后是一些中间层、数据分析层,或许还有一个 DLL 或 COM 对象,它们可以用本机代码、MFC 或 ATL 编写;最高层可能是一个提供用户界面的应用程序,它们可以用 Win32、MFC 或框架压缩版编写。

Platform Builder 和 Microsoft? eMbedded Visual C++? 都包括一个应用程序向导,它可以为应用程序创建 Win32 框架代码。框架代码包括对绘图(应用程序工作区中心的“Hello World”)、菜单(支持 File/Exit 和 Help/About)的支持,还包括 About 框的代码。

embedded02042003_fig1

1 :初具规模的 Win32 框架应用程序

对我们的任务来说,从框架代码入手是最好的选择,而且只有在这个时候,这些工具才会在我们开发 Win 32 应用程序的过程中发挥作用(当然,除此以外我们还会用到 eMbedded Visual C++ 附带的优秀联机帮助)。有了框架代码之后,我们需要手动编写其他所有内容。我们的示例应用程序要支持鼠标事件,因为没有向导可以帮助我们实现这个过程,所以我们要在 Windows 过程 (WndProc) 中插入相应的 WM_MOUSEMOVE、WM_LBUTTONDOWN 和 WM_LBUTTONUP 处理程序。好,下面介绍大家都喜欢使用的 switch 语句。

我喜欢调用独立的函数,而不喜欢使用大的 switch 语句来处理 WNDPROC 中的内联代码,因为这样可以使代码更容易阅读和调试。请记住,您可以通过在各个函数的入口点和出口点添加调试区域信息来动态跟踪应用程序的流程,从而借助“调试区域”执行调试进程。“调试区域”的一个优点是,您可以决定调试信息的级别以及何时需要该信息。如果到处使用 OutputDebugString,则会产生大量的调试信息,以至于淹没真正需要的信息。下面是我的 WNDPROC 的核心:

switch (message) {   case WM_COMMAND:      wmId    = LOWORD(wParam);       wmEvent = HIWORD(wParam);      
 // Parse the menu selections:
      switch (wmId)      {         case IDM_HELP_ABOUT:           
 DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, DLGPROC)About);            break;                  case ID_FILE_OPEN: 
           OpenScribbleFile(hWnd);                     break;         case ID_FILE_SAVE:            
SaveScribbleFile(hWnd);         break;            case IDM_FILE_EXIT:            CleanUp( );            
DestroyWindow(hWnd);         break;         default:            return DefWindowProc(hWnd, message, wParam, lParam);   
   }      break;   case WM_CREATE:      hwndCB = CommandBar_Create(hInst, hWnd, 1);          
     CommandBar_InsertMenubar(hwndCB, hInst, IDM_MENU, 0);      CommandBar_AddAdornments(hwndCB, 0, 0);      
Initialize( );      // setup the initial array element and mouse flags   break;   case WM_LBUTTONDOWN:  
    HandleLButtondown(hWnd,LOWORD(lParam),HIWORD(lParam));   break;      case WM_LBUTTONUP:      
HandleLButtonUp(hWnd,LOWORD(lParam),HIWORD(lParam));   break;      case WM_MOUSEMOVE:      
HandleMouseMove(hWnd,LOWORD(lParam),HIWORD(lParam));   break;   case WM_PAINT:     
 RECT rt;      hdc = BeginPaint(hWnd, &ps);      GetClientRect(hWnd, &rt);     
 LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);  
    DrawText(hdc, szHello, _tcslen(szHello), &rt,        
  DT_SINGLELINE | DT_VCENTER | DT_CENTER);    
  DrawArray(hWnd,ps);   
   EndPaint(hWnd, &ps);  
    break;   case WM_DESTROY:   
   CommandBar_Destroy(hwndCB); 
     PostQuitMessage(0);   
   break;   default:      
return DefWindowProc(hWnd, message, wParam, lParam);  }  return 0;}

我们还需要构建一个点数组,以保存 Scribble 数据。Win32 不提供任何用于处理数组的函数,因此我们需要自己创建链接表(因为我们希望动态地增加点的数量),或者在 Web 上找一个合适的数组类。这正是生活的乐趣所在。您可能会认为创建一个动态的点数组很简单,当然您可能是正确的。但我的画图处理程序代码却出了差错,结果超过了数组末尾,直接导致了访问冲突。我花了大约两个小时进行调试,最后终于查出并改正了问题(在包括 Win32 模板代码的 400 行的应用程序中 - 真是痛苦!)。使用 Win32,您可以随意调用任意 API、分配对象的生存期以及安排内存的使用方式。在我的示例中,我实在是太自由了。

下面是 POINT 结构的外观。我保留上次鼠标移动的 x 和 y 位置,还保留了指向数组中下一项的指针。我还计算了数组中的点数。因此,我可以遍历点的列表,并绘制项或将项写入文件。

typedef struct tag_ptArray{   POINT pt;   LPVOID ptrNext;} PTARRAY,*LPPTARRAY;

下面的代码显示我如何将一个点添加到一个反映鼠标移动的数组中。请注意,在完成该应用程序之后或者加载 Scribble 文件时,我们需要逐个检查列表中的各个元素并手动删除它们。否则我们将造成内存泄漏。

void AddElement(int X, int Y){   Current_Point->ptrNext=(LPPTARRAY)LocalAlloc(LPTR,sizeof(PTARRAY));  
 Current_Point=(LPPTARRAY)Current_Point->ptrNext;  
 Current_Point->pt.x=X;    Current_Point->pt.y=Y; 
  Current_Point->ptrNext=NULL;   iPointCount++;}

我们还需要显示一个用于打开(和保存)文件的对话框,以便获取和保存我们的 Scribble 数据。由于使用 Win32,因此需要用相应的元素填充一个 OPENFILENAME 结构,并调用 GetOpenFilename 来显示该对话框。从该点(完全故意双关)向前,我们可以使用 CreateFileWriteFile(或 ReadFile)和(这是 API 处理)CloseHandle(为什么不是 CloseFile 不?)。

void OpenScribbleFile(HWND hWnd){   
OPENFILENAME ofd;  
 TCHAR tcFileName[MAX_PATH]; 
  TCHAR tcDefaultName[MAX_PATH]; 
  wcscpy(tcDefaultName,L"Scribble.scr"); 
  memset(&ofd,0x00,sizeof(ofd));   
ofd.lStructSize=sizeof(ofd);   
ofd.hwndOwner=hWnd;   
ofd.hInstance=hInst;  
 ofd.lpstrFile=tcFileName;  
 ofd.nMaxFile=MAX_PATH;   
ofd.lpstrDefExt=L"scr"; 
  ofd.lpstrFilter=L"Scribble Files\0*.scr\0\0"; 
  ofd.lpstrTitle=L"Scribble Files";  
 ofd.Flags=OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST; 
  BOOL bRet=GetOpenFileName(&ofd);  
 if (TRUE == bRet) {      
CleanUp( );      
// clean up the existing scribble array   
   pt_Array=(LPPTARRAY)LocalAlloc(LPTR,sizeof(PTARRAY)); 
     Current_Point=pt_Array;  
    HANDLE hFile=CreateFile(ofd.lpstrFile,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);  
    POINT pt;      DWORD dwRead;      BOOL bRead=FALSE;      iPointCount=0;      while(TRUE) {   
      bRead=ReadFile(hFile,&pt,sizeof(pt),&dwRead,0);         if (dwRead) {            AddElement(pt.x,pt.y);
         } else            break;      }      CloseHandle(hFile);   }   InvalidateRect(hWnd,NULL,TRUE);}

编写(和调试)Win32 应用程序共需大约四个小时。最终生成一个 7 KB 大小的可执行文件,加载和执行该文件不需要任何额外的运行时。

Win32 API 使用起来非常有意思。有些函数接受多个参数,有些函数接受一个结构,有些函数返回一个指针,有些则返回一个操作系统在内部跟踪对象的句柄。而且,当我们使用对象之后,取决于对象的具体类型,我们需要删除、关闭或释放该对象。(如果不这样做,就会导致内存泄漏。)对于 4 个字节的句柄,这可能不是太大的问题,但如果数百万次地泄漏该句柄,则会很快耗尽设备的资源。如果您的设备要运行数小时、数周、数月甚至数年,这就会成为一个问题。所幸,我们有像 LMEMDEBUG、Memalyzer 和远程性能监视器这样的工具,能够帮助我们跟踪泄漏,还有像来自 Entrek 的 CodeSnitch 等其他好工具。所有这些工具在查找有漏洞的代码时都能助我们一臂之力。


 

Microsoft 基础类 (MFC)

MFC 对创建用于 Windows CE 的应用程序(或用于同一目的的桌面应用程序)有何作用呢?很简单。顾名思义,Microsoft 基础类提供了一组有用的类,这些类(在极大程度上)隐藏了 Win32 开发的复杂性。但有时候,您仍然需要直接调用 Win32 API。基于 Microsoft? .NET 框架压缩版的应用程序也是如此,这就是公开平台调用 (pInvoke) 的原因。

从 MFC 调用本机 API 非常简单。您只需像在编写本机 Win32 应用程序一样直接调用本机 Win32 API。如果看一下 MFC 源代码,您就会注意到 MFC 基本上就是在 Win32 API 之上加了一层薄薄的包装。MFC 附带了完整的源代码,这对于调试以及理解其内部运行情况非常有用。在 Windows CE .NET 4.1 上,如果默认安装了 eMbedded Visual C++,则可以在 C:\Program Files\Windows CE Tools\wce410\STANDARDSDK_410\Mfc\Src 中找到 MFC 源代码。

MFC 支持大约 160 个类

如需要阅读完整内容,请登录注册智谷联帐号

深圳市非常智联科技有限公司   深圳市智谷联软件技术有限公司
CopyRight © 2002-2011  SznewBest.Com  All Rights Reserved  经营许可证编号粤ICP备08019924号