65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 CAB Wizard 创建 Pocket PC 应用程序安装包 - 2

2004 年 7 月 15 日

CPOL

8分钟阅读

viewsIcon

103740

downloadIcon

215

一篇关于在Pocket PC应用程序安装包中实现自定义操作的文章。

引言

在我之前的文章 使用Cabwizard 1创建Pocket PC应用程序安装包 中,我们已经了解了如何使用Cabwizard工具创建应用程序的安装文件。在应用程序安装/卸载过程中,我们可能需要执行一些自定义操作,例如删除某些文件、在今日屏幕上添加新条目等。这些操作无法在生成的应用程序CAB文件中指定,因为它们在应用程序安装/卸载过程中执行。在这种情况下,我们可以编写一个DLL,并将其集成到CAB文件中。该DLL将在应用程序安装和卸载期间被调用。本文将详细介绍如何创建此DLL并将其集成到应用程序的CAB文件中。

阅读本文后,您将了解:

  • 为什么需要在CAB文件中实现自定义操作?
  • 如何将自定义操作与CAB文件集成?

必备组件

所需工具

什么是自定义操作?

自定义操作是在应用程序安装/卸载过程中执行的一段代码。

在应用程序安装/卸载过程中需要自定义操作的原因是什么?

  • 清理Pocket PC应用程序创建的文件
  • 安装Pocket PC应用程序正常运行所需的外部或运行时库,例如.NET Compact Framework
  • 执行外部应用程序

案例研究

假设有一个Pocket PC应用程序,提供添加/修改/删除/查看数据库数据的选项。数据库在您第一次启动应用程序时创建。您启动应用程序,填充数据,对其进行操作并查看数据。但是,当您从设备上卸载该应用程序时,应用程序并未正确卸载。您会收到一条消息,提示某些文件未被删除。

为什么?因为应用程序在首次启动时创建了数据库文件。无论是在应用程序安装到设备时复制还是创建的文件(除了共享文件,如COM对象),在设备上卸载应用程序时都会被自动删除。但是,在应用程序安装后或在运行时创建的文件、数据库或日志文件等不会被删除。在这种情况下,我们可以使用自定义操作来完成这些清理任务。

何时可以执行自定义操作?

  • 在安装过程开始之前
  • 在安装过程结束之后
  • 在卸载过程开始之前
  • 在卸载过程结束之后

因此,基本上在VB术语中,我们将为这些事件编写事件处理程序,并将代码附加到CAB文件中。

谁执行自定义操作?

在安装/卸载过程中,WCELOAD.exe 会调用这些事件处理程序来执行CAB文件。这些事件处理程序只能用WIN32或MFC DLL编写,并集成到CAB文件中。请注意,这无法使用.NET CF来实现。有四个需要从DLL导出的事件处理程序或函数:

  • Install_Init
  • Install_Exit
  • Uninstall_Init
  • Uninstall_Exit

顾名思义,`Install_Init()` 在安装过程开始前调用。`Install_Exit()` 在安装过程结束后调用。`Uninstall_Init()` 在卸载过程开始前调用,`Uninstall_Exit()` 在卸载过程结束后调用。

如何使用CAB文件实现自定义操作

我们将通过一个示例来了解如何使用CAB文件实现自定义操作。以下是为该示例需要实现的分步过程:

  • 创建一个简单的EVB应用程序
  • 使用应用程序安装向导生成EVB应用程序的安装包
  • 创建一个包含在安装和卸载过程中调用的自定义代码的WIN32 DLL
  • 将DLL集成到生成的CAB文件中。

创建EVB应用程序

  • 打开EVB并创建一个名为TestApp的新Pocket PC 2002项目
  • 将Form的ShowOK属性设置为true
  • 通过选择Project => References包含SQL CE、ADOCE 3.1、ADOXCE库。
  • 向窗体添加一个Command Button,将其Name属性设置为'cmdcreate'
  • 在按钮的Click事件中包含以下代码:

    Private Sub cmdcreate_Click()
        On Error Resume Next
        'local variables
        Dim objcatalog As ADOXCE.Catalog
        Dim strconn As String
    
        'create catalog object
        Set objcatalog = CreateObject("ADOXCE.Catalog.3.1")
    
        'set connection string
        strconn = "Provider=Microsoft.SQLSERVER.OLEDB.CE.2.0; data source=" 
               & App.Path & "\test.sdf"
        'MsgBox strconn
    
        'create database
        objcatalog.Create strconn
    
        'check for errors
        If Err.Number <> 0 Then
        MsgBox Err.Number & " : " & Err.Description, , "error"
        Else
        MsgBox "database created"
        End If
    
        'destory catalog object
        Set objcatalog = Nothing
    End Sub
                        
  • 选择File => Make TestApp.vb。现在EVB应用程序已准备就绪。

使用应用程序安装向导生成EVB应用程序的安装包

  • 选择Tools => Remote Tools => Application Install Wizard
  • 按照向导中的步骤操作

创建一个包含在安装和卸载过程中调用的自定义代码的WIN32 DLL

  • 启动EVC++并创建一个名为'setupdll'的空WCE动态链接库项目
  • 向项目添加一个头文件'ce_setup.h'。此头文件包含上述4个函数的声明,通常位于Pocket PC SDK安装路径下的\Windows CE Tools\wce300\Pocket PC 2002\include子目录中。将该文件复制到您的项目目录,并通过选择Project => Add to Project => Files并选择该文件将其包含在项目工作区中。
  • 要添加源文件,请选择File => New => C++ source file。在Filename字段中输入'setupdll',然后单击OK按钮。将创建一个名为'setupdll.cpp'的新文件并将其包含在项目工作区中。
  • 在.cpp文件中包含以下代码:

    #include <windows.h> 
    #include "ce_setup.h"
    
    ///////////////////////////////////////////////////////////
    //PURPOSE : HANDLES TASKS DONE AT START OF INSTALLATION
    ///////////////////////////////////////////////////////////
    codeINSTALL_INIT Install_Init(HWND hwndparent,
      BOOL ffirstcall,BOOL fpreviouslyinstalled,LPCTSTR pszinstalldir)
    {
        //do nothing
        //return value
        return codeINSTALL_INIT_CONTINUE;
    }
    
    ///////////////////////////////////////////////////////////
    //PURPOSE : HANDLES TASKS DONE AT END OF INSTALLATION
    ///////////////////////////////////////////////////////////
    codeINSTALL_EXIT Install_Exit(
        HWND hwndparent,LPCTSTR pszinstalldir,
        WORD cfaileddirs,WORD cfailedfiles,WORD cfailedregkeys,
        WORD cfailedregvals,
        WORD cfailedshortcuts)
    {
        //do nothing
        //return value
        return codeINSTALL_EXIT_DONE;
    }
    
    ///////////////////////////////////////////////////////////////
    //PURPOSE : HANDLES TASKS DONE AT BEGINNING OF UNINSTALLATION
    ///////////////////////////////////////////////////////////////
    codeUNINSTALL_INIT Uninstall_Init(
      HWND hwndparent,LPCTSTR pszinstalldir)
    {
        //local variables    
        WIN32_FIND_DATA findfiledata;
        HANDLE hfind;
        TCHAR pszfilepath[50];
    
        //initialize character array
        memset(pszfilepath,0,sizeof(pszfilepath));
    
    
        //copy database path to character array
        //pszinstalldir variable will contain the 
        //application path (eg : \Program Files\TestApp)
        wcscpy(pszfilepath,pszinstalldir);
        wcscat(pszfilepath,TEXT("\\test.sdf"));
    
        //trying to find whether database file exists or not
        hfind = FindFirstFile(pszfilepath,&findfiledata);
    
        if(hfind != INVALID_HANDLE_VALUE) //database file exists
        {
            //delete database
            DeleteFile(pszfilepath);
        }
    
        //return value
        return codeUNINSTALL_INIT_CONTINUE;
    }
    
    
    ///////////////////////////////////////////////////////////
    //PURPOSE : HANDLES TASKS DONE AT END OF UNINSTALLATION
    ///////////////////////////////////////////////////////////
    codeUNINSTALL_EXIT Uninstall_Exit(HWND hwndparent)
    {
        //do nothing
        //return value
        return codeUNINSTALL_EXIT_DONE;
    }
    
                    
  • 现在我们已经添加了DLL的代码。在`Uninstall_Init()`中(在卸载过程开始时调用),我们检查数据库文件是否存在,如果存在则将其删除。这就是DLL。
  • 为了使函数能够从外部应用程序访问,我们需要将其设为public。这个过程称为“导出”。为此,请通过选择File => New => Text File创建一个.def文件。将其命名为setupdll.def并按OK。该.def文件包含DLL导出的函数或符号。在文件中包含以下行:

    EXPORTS
        Install_Init
        Install_Exit
        Uninstall_Init
        Uninstall_Exit
                        
  • 通过选择Build => Build setupdll.dll来编译ARM和X86平台的DLL。通过选择Build => Set Active Configuration来设置编译DLL的相应平台。

将DLL集成到生成的CAB文件中

现在我们需要将DLL集成到安装包中。Cabwizard通过读取.inf文件来生成安装包。我们将编辑.inf文件,在.inf文件中包含setup dll的路径,然后再次调用Cabwizard实用程序,并将此.inf文件作为参数来生成安装包。以下是将setup dll与CAB文件集成的步骤:

  • 导航到生成设置文件的目录。如果安装包已正确生成,该目录将包含以下子目录:App、Arm 1100 (4K) v3.00、I486 (4K) v3.00、CD1以及以下文件:Readme.txt、TestApp.inf。
  • 将为ARM和X86平台编译的DLL文件分别复制到Arm 1100 (4K) v3.00和I486 (4K) v3.00目录中。
  • 打开TestApp.inf文件,并从.inf文件中删除以下部分:[CEDevice.I486 (4K) v3.00]和[CEDevice.Arm 1100 (4K) v3.00]。如果这些部分存在,CAB文件将不会在Pocket PC模拟器中执行。
  • 导航到[DefaultInstall]部分,并在其他键之前插入键/值CESETUPDLL="setupdll.dll"。通过此条目,我们指定从setupdll.dll执行自定义操作。
  • 现在我们需要提供DLL的路径信息。为此,请在[SourceDisksFiles.I486 (4K) v3.00]和[SourceDisksFiles.Arm 1100 (4K) v3.00]部分的末尾添加条目setupdll.dll=3。
  • 在[Files.I486 (4K) v3.00]和[Files.Arm 1100 (4K) v3.00]部分的末尾添加条目setupdll.dll,,0x80000000。

有关.inf文件的更多详细信息,请参阅我之前的 文章

好了,.inf文件已准备就绪。现在我们需要调用Cabwizard实用程序,并将.inf文件作为参数传入。为此,请打开Readme.txt文件。按照文件中提供的指示,将命令行文本复制到命令提示符并执行它。如果一切顺利,CAB文件应该会在由Application Install Wizard实用程序创建的设置文件的目录中生成。将CAB文件复制到CD1文件夹。

测试CAB文件

现在,让我们看看setup dll是否被调用。在Pocket PC设备上测试时,只需执行CD1目录中的setup.exe文件,然后为ARM平台生成的CAB文件会自动复制到设备并执行。在Pocket PC模拟器的情况下,复制为X86平台生成的CAB文件并执行该文件。应用程序将安装。调用EVB应用程序。通过单击“create”命令按钮创建SQL Server CE数据库,然后关闭应用程序。现在,选择Start Menu => Settings => System => Remove Programs,然后单击TestApp应用程序并单击Remove按钮。该应用程序被干净地移除。我们的自定义操作代码在卸载过程之前执行,删除了数据库文件。

结论

至此,我们了解了如何将自定义操作集成到CAB文件中,从而使我们的应用程序安装包更加强大和功能丰富。希望在我下一篇文章中,我们将讨论如何将自定义COM DLL集成到CAB文件中。请对本文提出宝贵的建议。

参考文献

© . All rights reserved.