目前有三个选项可供针对 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 个类、包装窗口、视图、文档、时间、数组、字符串、套接字以及笔、画笔等 GDI 对象。可以在 Web 或 eMbedded Visual C++ product documentation 上查看受支持的类的列表。

桌面 MFC 与 Windows CE MFC 在实现方面存在一些差异。Differences from Desktop 突出介绍了这些差异。

基于 MFC 的应用程序是使用 eMbedded Visual C++ 4.0 创建的,可以从 here 下载该工具。用于 Windows CE 的基于 MFC 的应用程序只能使用此工具创建。Platform Builder 只能创建 Win32 应用程序和 DLL。

eMbedded Visual C++ 通过 eMbedded Visual C++ 工具和支持的 MFC 类,协助您进行应用程序的开发。如果我们回顾一下 Win32 应用程序,若要为诸如 WM_LBUTTONDOWN(鼠标按钮按下,此操作是由单击鼠标或用笔尖触击触摸屏生成)这样的 Windows 消息添加支持,则需要通过在 WNDPROC switch 中添加更多的 case 语句来修改应用程序的 WNDPROC。我们还需要知道如何将 WPARAM 和 LPARAM 参数转换为设备坐标。通过 MFC,我们可以使用 MFC 类向导(Ctrl+W 或从菜单中调用)来创建窗口消息处理程序(无需更多的 switch 语句)。消息处理程序分解消息参数,然后将某些更适用的参数传递给 MFC 消息处理程序。下面是 MFC 类向导的外观。

embedded02042003_fig2

2MFC 类向导

您也可以在类上右键单击,并选择 Windows Message Handler

embedded02042003_fig3

3Windows 消息处理程序

那么,典型的 MFC Windows 消息处理程序是什么样子的呢?我们来看类向导为 WM_LBUTTONDOWN 消息生成的一个函数。可以清楚地看见我们传递了鼠标状态标记(表示按下哪个鼠标按钮),和 CPoint(包含按下鼠标时的 x 和 y 位置)。

void CMFCScribbleView::OnLButtonDown(UINT nFlags, CPoint point)
{
   m_InDraw=true;
   m_CurrentPoint=point;

   CView::OnLButtonDown(nFlags, point);
}

void CMFCScribbleView::OnLButtonUp(UINT nFlags, CPoint point)
{
   m_InDraw=false;
   m_CurrentPoint=CPoint(0,0);

   CView::OnLButtonUp(nFlags, point);
}

void CMFCScribbleView::OnMouseMove(UINT nFlags, CPoint point)
{
   if (m_InDraw) {
      if (point != m_CurrentPoint) {
         CPoint line[2];
         line[0]=m_CurrentPoint;
         line[1]=point;
         m_CurrentPoint=point;
         CDC *pDC=GetDC( );
         pDC->Polyline(line,2);
         ReleaseDC(pDC);
      }
   } else
      CView::OnMouseMove(nFlags, point);
}

上面的代码是绘制鼠标实际移动情况所需的全部代码。我们获取鼠标移动处理程序中的设备上下文(使用 GetDC),绘制一条从前一点到当前位置的线条(使用 Polyline)。这段代码运行一切正常,但如果我们的工作区由于某种原因而无效,就会丢失其中的内容。理想情况下,我们应该保留一个点列表,我们可以使用 Win32 示例中相同的链接列表代码。如果 MFC 能为我们处理这个问题就好了。MFC 附带了对标准模板库的支持,它提供的诸如 CArray 这样的类可以用来存储我们的点列表。

下面是创建 CArray 和将点添加到数组的示例。数组随着点的增加而动态扩大。当我们加载 scribble 文件时清理数组是很简单的,只需调用 myArray.RemoveAll( );。这比使用 Win32 应用程序要容易得多。编写 Win32 应用程序时,利用 CArray 为我节省了将近一小时时间。

CArray myArray;

// Add elements to the array.
for (int i=0;i < 10;i++)
    myArray.Add( CPoint(i, 2*i) );

这样,我们只需要将一个 CArray <CPoint, CPoint> myArray 成员变量添加到文档类中,并将 OnMouseMove 处理程序修改为将新的点添加到类中。

void CMFCScribbleView::OnMouseMove(UINT nFlags, CPoint point)
{
   if (m_InDraw) {
      if (point != m_CurrentPoint) {
         CPoint line[2];
         line[0]=m_CurrentPoint;
         line[1]=point;

         // add the new point to the document.
         GetDocument( )->myArray.Add(point);
         // add the new point to the document.

         m_CurrentPoint=point;
         CDC *pDC=GetDC( );
         pDC->Polyline(line,2);
         ReleaseDC(pDC);
      }
   } else
      CView::OnMouseMove(nFlags, point);
}

然后就可以在 OnDraw 处理程序中回放这些点,如下所示:

void CMFCScribbleView::OnDraw(CDC* pDC)
{
   CMFCScribbleDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);

   int iCount=pDoc->myArray.GetSize( );
   POINT *pt=new POINT[iCount];
   for (int x=0;x < iCount;x++) {
      pt[x].x=pDoc->myArray.GetAt(x).x;
      pt[x].y=pDoc->myArray.GetAt(x).y;
   }
   pDC->Polyline(pt,iCount);
   delete [] pt;
}

现在,我们可以在应用程序的工作区随意涂写,并在需要重画工作区时回放 Scribble。最后一步是存储和加载 Scribble 数据。使用 CArray 保存 CPoint 数组有一个弊端:CArray 支持一个称为 Serialize 的方法,并且我们的 Scribble 应用程序的 CDocument 类包括一个称为 Serialize 的函数。传递给此函数一个 CArchive 对象,该对象用于以删除对象后仍然继续存在的持久性二进制形式(通常是磁盘存储)保存一个复杂的对象网络。我们只需在 Serialize 函数中添加两行代码,如下所示。

void CMFCScribbleDoc::Serialize(CArchive& ar)
{
   if (ar.IsStoring())
   {
      // Store the Array of lines
      myArray.Serialize(ar);
   }
   else
   {
      // restore the Array of lines
      myArray.Serialize(ar);
   }
}

编写、测试和调试 MFC 应用程序总共需要大约两个小时。发布的应用程序大小约为 18 KB。不难看出,MFC 提供了许多有用的类,使您可以集中精力编写应用程序代码,尽管您仍然需要经常调用本机 Win32 API,但不必在底层操作系统提供的 API 上花费太多的时间。

返回页首返回页首

框架压缩版

接下来,让我们看看使用 Microsoft .NET 框架压缩版编写 Scribble 应用程序的情况。我决定先将其作为桌面应用程序编写和测试,然后再将代码移植到 Windows CE 中。这是一种有意思的练习,我会在移植代码后解释为什么。

构建框架压缩版应用程序的开发环境有点类似 Microsoft_ Visual Basic_ 开发。如果您需要菜单、常用的文件对话框或其他控件,只需要从工具箱中将这些内容拖放到窗体中,然后设置控件的属性,编写控件的附加代码。

embedded02042003_fig4

4. 设备控件工具箱

我们需要添加用于按下鼠标、移动鼠标和释放鼠标的处理程序。这很简单。使用窗体属性对话框(参见下图)可以为典型的基于窗体的消息添加处理程序:按下/释放键、按下/释放/移动鼠标,等等。然后,我们编写处理程序的代码。

embedded02042003_fig5

5. 应用程序窗体属性

embedded02042003_fig6

6. Scribble 应用程序中使用的控件

请注意,这些控件没有设计时 UI。但是,大多数框架压缩版控件都有一种设计时调整机制,使您可以在一个近似于“所见即所得”的环境中排列窗体上的控件并调整控件的大小。

将三个变量添加到类中:

...public bool bMouseDown=false;
...public ArrayList m_myAL;
...public Point m_CurrentPoint;

下面是用于按下鼠标、移动鼠标和释放鼠标的处理程序。注意,我们是在鼠标移动中创建 System.Drawing.Graphics 对象。因此,我们可以从上一点向当前点绘制一条线,而不需要使客户端区域无效。

private void Form1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
bMouseDown=false;
}

private void Form1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
   if (true == bMouseDown)
   {
      m_myAL.Add(new Point(e.X,e.Y));
      System.Drawing.Graphics gr=this.CreateGraphics( );
      Pen myPen=new Pen(System.Drawing.Color.Black);
         gr.DrawLine(myPen,m_CurrentPoint.X,m_CurrentPoint.Y,e.X,e.Y);
      m_CurrentPoint.X=e.X; m_CurrentPoint.Y=e.Y;
   }
}

private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
   bMouseDown=true;
   m_CurrentPoint.X=e.X;
   m_CurrentPoint.Y=e.Y;
}

我们需要更新(创建一个新的对象实例)ArrayList。我在窗体加载时处理该操作。

private void Form1_Load(object sender, System.EventArgs e)
{
      m_myAL = new ArrayList();
}

接下来是用于从文件系统读回 Scribble 文件的代码。这正是编写应用程序的乐趣所在。我起初使用了 BinaryFormatter 类,它可以利用 BinarayFormatter.Serialize( ) 函数序列化整个 ArrayList。从文件读回 ArrayList 与使用 BinaryFormatter.DeSerialize( ) 函数一样简单。在我将代码移植到框架压缩版之前,应用程序的构建、测试和运行都非常顺利。但结果还是构建失败:框架压缩版不支持 BinaryFormatter。现在只好重新编写代码。

在这种情况下,我决定使用 BinaryReader/Writer 将各个点写出到流。我先写入项数,然后写入各个项本身。下面是将 ArrayList 写入到文件的代码。注意,我不需要指定我所写入的对象类型。我只是调用 Foo.Write(m_myAL.Count),即可将元素的数目写入到文件。

...BinaryWriter Foo=new BinaryWriter(myStream);
...Foo.Write(m_myAL.Count);
   foreach (Point p in m_myAL)
   {
      Foo.Write(p.X); Foo.Write(p.Y);
   }
   Foo.Close( );
   myStream.Close();

一切都运行正常。现在,从文件读回信息时,我需要调用 Foo.Read 以便从文件读回适当的大小。(假定您知道文件中包含什么内容,因为您很可能首先创建了该文件。)我可以使用代码 Console.WriteLine ("X is a {0}",p.x.GetType); 来指定对象类型,在这里,类型是 Int32。因此,我的反序列化代码将调用 Foo.ReadInt32( );,以便读取项的数目和各个 x 和 y 元素。

private void FileOpen_Click(object sender, System.EventArgs e)
{
   openFileDialog1.Filter = "Scribble files (*.scr)|*.scr";
   openFileDialog1.FilterIndex = 1;
   if (openFileDialog1.ShowDialog( ) == DialogResult.OK)
   {
      Stream myStream = File.OpenRead(openFileDialog1.FileName);
      if (myStream != null)
      {
         BinaryReader Foo=new BinaryReader(myStream);
         int iCount=Foo.ReadInt32( );
         Point p=new Point(0,0);
         for (int x=0; x < iCount;x++)
         {
            p.X=Foo.ReadInt32( );
            p.Y=Foo.ReadInt32( );
            m_myAL.Add(p);
         }
         Foo.Close( );
         myStream.Close();
         this.Refresh();
      }
   }
}

那么,编写和测试要花费多长时间呢?整个应用程序在 20 分钟内编写完毕并运行良好,再用 5 分钟左右将 BinaryFormatter 代码更改为 BinaryReader,编写整个应用程序从头到尾共需要不到 30 分钟。桌面应用程序的大小为 28 KB,在设备上为 7 KB。(不要忘记应用程序还需要 1.5 MB 的框架的支持。)

返回页首返回页首

小结

也许您希望尽快知道使用哪个运行时好。下面是您做决定时要考虑的因素:是否您有现成的 Win32/MFC/C#/Visual Basic 代码、正在编写的代码的类型(驱动程序、实时、应用程序)、包括应用程序和运行时在内的最终操作系统映像的总大小、开发应用程序的速度以及其他诸如安全性和可移植性等因素。好在您可以自行选择,还可以根据所执行的项目层有针对性地利用代码:驱动程序使用 Win32,最终用户应用程序使用 Win32、MFC 或 C#/Visual Basic。本文主要向应用程序开发人员说明利用桌面编程知识确实可以快速提高 Windows CE 的开发效率。


评论

该日志第一篇评论

发表评论

评论也有版权!