自动将多个 CAB 文件安装到 Windows Mobile/Pocket PC 设备






4.71/5 (7投票s)
一个使用多线程和 ActiveSync 自动将多个 CAB 文件安装到 Windows Mobile 或 Pocket PC 设备的解决方案
引言
本文旨在描述一种解决方案,该解决方案利用多线程和 ActiveSync 来自动化将多个 CAB 文件安装到 Windows Mobile 或 Pocket PC 设备的过程。
包含的示例安装项目是一个标准的 Windows MSI 安装文件,运行该文件将把两个 CAB 文件安装到 Windows Mobile 或 Pocket PC 设备。
项目包含的自定义操作负责将 CAB 文件安装到设备,它使用 ActiveSync 一次一个地连续安装每个 CAB 文件。每个安装都在一个单独的线程中运行,主进程在继续下一个安装之前会等待每个安装完成。
出于示例目的,我包含了两个 CAB 文件,但自定义操作可以轻松扩展以安装您想要的任意数量的 CAB 文件。包含的 CAB 文件将安装 .NET Compact Framework 3.5 和 SQL Mobile 2.0。
描述
自定义操作通过重写和扩展 `Installer` 类的默认功能来工作。安装程序类的被重写 `Commit` 方法首先调用基类的 `Commit` 方法,然后继续实现自定义功能。
大致而言,自定义功能的工作原理如下:
- 所有 CAB 文件都由安装程序复制到初始安装目标目录。MSI 会自动执行此操作。
- 自定义操作然后初始化一个 `InstallParams` 对象,该对象接受一个 `AutoResetEvent` 对象(用于在线程终止时发出信号)和一个标识要安装的 CAB 的初始化(*.ini*)文件的字符串。
- `RunInstallerTask` 方法和 `InstallParams` 对象用于通过调用 `ThreadPool.QueueUserWorkItem` 来启动一个新线程。
- 新线程启动一个进程,即执行一个程序,在本例中是 ActiveSync。如果安装了 ActiveSync,ActiveSync 的默认安装目录将从注册表项中检索:HKEY_LOCAL_MACHINE\Software\microsoft\windows\currentversion\app paths\ceappmgr.exe。
- 在 ActiveSync 执行和安装目标 CAB 的同时,新(正在执行)的线程会等待,每隔 1000 毫秒间歇性地检查 `Process` 类的 `Process.HasExited` 属性。当进程退出时,它通过调用 `AutoResetEvent` 对象的 `Set()` 方法来向 `AutoResetEvent` 发出信号。这会向调用线程发出信号,该线程一直处于高效等待状态(通过调用 `AutoResetEvents` 的 `WaitOne` 方法),以继续执行。
- 从步骤 II 开始的过程会为将要安装的任何后续 CAB 文件重复执行。
实现
InstallParams 类
`InstallParams` 类很容易理解。如前所述,它只包含一个 `AutoResetEvent` 对象和一个包含 CAB 文件安装初始化文件(*.ini*)的字符串。`InstallParams` 对象作为第二个参数传递给 `ThreadPool.QueueUserWorkItem`。
此类作为嵌套的公共类实现,是 `CABFileInstaller` 类的一部分。
CABFileInstaller 类
此类派生自 `Installer` 类(声明为 partial
,因此是标准库基类 `Installer` 类的派生扩展)。唯一重写 `Installer` 类的方法是 Commit 方法,该方法在实现任何自定义功能之前调用基类的 `Commit` 方法。
此类有一个私有的字符串成员(string appPath
),用于存储 ActiveSync 可执行文件的路径。
此派生类还有一个名为 `RunInstallerTask` 的附加私有方法,该方法启动 ActiveSync 并基于 *.ini* 文件(下文所述)中的信息安装 CAB 文件。此方法依赖于作为其上下文一部分传递给安装过程的信息,以确定目标目录的路径。
`RunInstallerTask` 方法中的行 strIniFilePath = "\"" + Context.Parameters["targetdir"]...
从当前上下文中确定目标安装目录。为了实现这一点,必须将自定义操作的 `CustomActionData` 属性设置为 /targetdir="[TARGETDIR]\",如下面的演练中所述。
初始化文件(.ini)
对于要安装的每个 CAB 文件,必须创建一个格式化的 *.ini* 文件并将其安装到 MSI 目标目录。MSI 会自动将文件传输到安装文件夹,但您必须为每个 CAB 创建 ini 文件并将其添加到安装项目中的 ApplicationFolder 包含的文件中。
有关 *.ini* 文件内容及其格式的详细信息,请参阅 MSDN 上的此 URL:http://msdn.microsoft.com/en-us/library/bb158614.aspx。
对于一个简单的 .ini 文件示例,用于安装 .NET Compact Framework CAB 文件(包含示例中的 NETCFv35.ini)的 .ini 文件如下所示:
[CEAppManager]
Version = 1.0
Component = NETCFv35.ppc.armv4
[NETCFv35.ppc.armv4]
Description = RMS Stock Count Client
CabFiles = NETCFv35.ppc.armv4.cab
前两行永远不变,即 `[CEAppManager]`,版本必须始终为 1.0。
`Component` 值必须与下一节的开头匹配,而最后一个(`CabFiles`)值应与正在安装的 CAB 文件的确切名称匹配。可以包括多个 CAB 文件在最后一行,用逗号分隔,以支持不同的体系结构。在本例中,包含的 .NET Compact Framework CAB 文件适用于 ARM 处理器。
项目设置 - 演练
我使用了 Visual Studio 2008,但这应该适用于 VS2005。
创建自定义操作
- 在 **文件** 菜单上,单击 **新建项目**。
- 在 **新建项目** 对话框中,在 **项目类型** 窗格中选择 **Visual C# 项目**,然后单击 **模板** 窗格中的 **类库**。在 **名称** 框中,键入 CABInstallCustomAction。
项目已添加到 **解决方案资源管理器**。
- 在 **项目** 菜单上,单击 **添加类**,然后在 **添加新项** 对话框中,选择 **安装程序类**。键入名称为 CABFileInstaller.cs。单击 **添加**。
- 通过单击设计图面上的 **单击此处切换到代码视图**(或右键单击设计图面并单击 **查看代码**)切换到代码视图。
- 在代码编辑器中,将以下代码添加到 CABFileInstaller.cs 的类声明之后(也可以参阅本文附带的示例解决方案中的同一文件):
声明 `InstallParams` 类
public class InstallParams { private AutoResetEvent reset; private string strIniFile; public InstallParams(AutoResetEvent ev, string ini_file) { if (ev == null) throw new Exception("Null reset event"); reset = ev; strIniFile = ini_file; } public AutoResetEvent Reset { get { return reset; } } public string IniFile { get { return strIniFile; } } }
声明私有字符串 appPath
private string appPath = null;
创建 `RunInstallTask` 方法
private void RunInstallerTask(Object iparam) { int time = 0; InstallParams iparams = iparam as InstallParams; AutoResetEvent are = (AutoResetEvent)iparams.Reset; // Get the target directory where the .ini file is installed. // This is sent from the Setup application string strIniFilePath = "\"" + Context.Parameters["targetdir"] + iparams.IniFile + "\""; // Now launch the Application Manager - ActiveSync System.Diagnostics.Process process = new System.Diagnostics.Process(); process.StartInfo.FileName = appPath; process.StartInfo.Arguments = strIniFilePath; process.Start(); while (!process.HasExited) { time = 1000; Thread.Sleep(time); } are.Set(); }
创建重写的 `Commit` 方法
public override void Commit(System.Collections.IDictionary savedState) { // Call the Commit method of the base class base.Commit(savedState); AutoResetEvent ev; InstallParams ip; Microsoft.Win32.RegistryKey key = null; // Open the registry key containing the path to the Application Manager key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( "Software\\microsoft\\windows\\currentversion\\app paths\\ceappmgr.exe"); // If the key is not null, then ActiveSync // is installed on the user's desktop computer if (key != null) { // Get the path to the Application Manager from the registry value appPath = key.GetValue(null).ToString(); if (appPath != null) { //.Net 3.5 ev = new AutoResetEvent(false); ip = new InstallParams(ev, "NETCFv35.ini"); ThreadPool.QueueUserWorkItem(new WaitCallback(RunInstallerTask), ip); ev.WaitOne(); //SQL ev = new AutoResetEvent(false); ip = new InstallParams(ev, "sql.ini"); ThreadPool.QueueUserWorkItem(new WaitCallback(RunInstallerTask), ip); ev.WaitOne(); } } else { // No Active Sync - throw an error message throw new Exception("ActiveSync Not Installed"); } }
- 在 **解决方案资源管理器** 中,右键单击 Class1.cs,然后单击 **删除**(因为它是不必要的)。
添加部署项目
- 在 **文件** 菜单上,指向 **添加**,然后单击 **新建项目**。
- 在 **添加新项目** 对话框的 **项目类型** 窗格中,展开 **其他项目类型** 节点,然后选择 **设置和部署项目**。在 **模板** 窗格中,单击 **设置项目**。在 **名称** 框中,键入 **MultipleCABFilesSetup**。
项目已添加到 **解决方案资源管理器**,并且 **文件系统编辑器** 已显示。将 CAB 文件和相应的 *.ini* 文件复制到项目文件夹。
- 在 **文件系统编辑器** 中,在左侧窗格中选择 **应用程序文件夹**。在 **操作** 菜单上,指向 **添加**,然后单击 **文件**。以这种方式将所有 CAB 文件和相应的 *.ini* 文件添加到应用程序文件夹。
- 在 **文件系统编辑器** 中,在左侧窗格中选择 **应用程序文件夹**。在 **操作** 菜单上,指向 **添加**,然后单击 **项目输出**。
- 在 **添加项目输出组** 对话框中,将在 **项目** 列表中显示 **CABInstallCustomAction**。选择 **主要输出**。
**CABINstallCustomAction 的主要输出(活动)** 出现在 **应用程序文件夹** 中。
添加自定义操作
- 在 **解决方案资源管理器** 中选择 **MultipleCABFilesSetup** 项目。在 **视图** 菜单上,指向 **编辑器**,然后单击 **自定义操作**。
**自定义操作编辑器** 将显示。
- 在 **自定义操作编辑器** 中,选择 **安装** 节点。在 **操作** 菜单上,单击 **添加自定义操作**。
- 在 **在项目中选择项** 对话框中,双击 **应用程序文件夹**。选择 **CABInstallCustomAction 的主要输出**。
**CABInstallCustomCation 的主要输出** 出现在 **自定义操作编辑器** 的 **安装** 节点下。
在 **属性** 窗口中,将以下行添加到 **CustomActionData** 属性:/targetdir="[TARGETDIR]\"。此数据将传递给自定义操作,以便在目标安装目录中查找 ini 和 CAB 文件。请参阅自定义操作代码。
- 在 **属性** 窗口中,确保 **InstallerClass** 属性设置为 **True**(这是默认设置)。
- 在 **自定义操作编辑器** 中,选择 **提交** 节点。在 **操作** 菜单上,单击 **添加自定义操作**。
- 在 **在项目中选择项** 对话框中,双击 **应用程序文件夹**。选择 **CABInstallCustomAction 的主要输出**。
**CABInstallCustomCation 的主要输出** 出现在 **自定义操作编辑器** 的 **提交** 节点下。
在 **属性** 窗口中,将以下行添加到 **CustomActionData** 属性:/targetdir="[TARGETDIR]\"。此数据将传递给自定义操作,以便在目标安装目录中查找 ini 和 CAB 文件。请参阅自定义操作代码。
- 在 **属性** 窗口中,确保 **InstallerClass** 属性设置为 **True**(这是默认设置)。
- 在 **生成** 菜单上,单击 **生成自定义操作安装程序**。
在开发计算机上安装
- 确保目标设备已连接,并且已使用 ActiveSync 设置了伙伴关系。然后,在 **解决方案资源管理器** 中选择 **MultipleCABFilesSetup** 项目。在 **项目** 菜单上,单击 **安装**。
这将运行安装程序并在您的开发计算机上安装 **MultipleCABFilesSetup**。安装结束时,您应该会看到 ActiveSync 启动并提示您安装 .NET Compact Framework,然后是 SQL Client。
部署到另一台计算机
- 在 **Windows 资源管理器** 中,导航到您的项目目录并找到安装程序。默认路径将是 \Documents and Settings\<yourloginname>\My Documents\Visual Studio\Projects\MultipleCABFilesSetup\ MultipleCABFilesSetup \<project configuration>\ MultipleCABFilesSetup.msi。默认的 project configuration 是 **Debug**。
- 将自定义操作 Installer.msi、Setup.exe 以及该目录中的所有其他文件和子目录复制到另一台计算机。要在一台未联网的计算机上安装,请将文件复制到 CD-ROM 等传统媒体。
- 在目标计算机上,确保已安装 ActiveSync,目标设备已连接,并且已使用 ActiveSync 设置了伙伴关系,然后双击 Setup.exe 运行安装程序。
安装结束时,ActiveSync 应该会启动,并提示您安装设置项目中包含的两个 CAB 文件。
您必须在计算机上拥有安装权限才能运行安装程序。
卸载应用程序
- 在 **控制面板** 中,双击 **添加或删除程序**。
- 在 **添加或删除程序** 对话框中,选择 **MultipleCABFileSetup** 并单击 **删除**。要从您的开发计算机卸载,请在 **解决方案资源管理器** 中打开并选择 **MultipleCABFileSetup** 项目,然后从 **项目** 菜单中单击 **卸载**。