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

通过 RAPI 解压

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (3投票s)

2007年8月21日

CPOL

7分钟阅读

viewsIcon

41030

downloadIcon

359

通过 ActiveSync 连接解压缩文件。

引言

本文介绍了通过 ActiveSync (RAPI) 连接解压缩 ZIP 文件的三种解决方案。ZIP 文件可以从设备解压到 PC,也可以从 PC 解压到设备。

背景

最近,一位客户要求我升级一个专业的移动应用程序安装程序。该移动应用程序运行在各种设备上,从 Pocket PC 到专业的 Windows CE 设备,其中一些设备甚至不被 ActiveSync 识别为设备(它们显示为存储设备)。使用常规的 cab 安装程序是不可能的,而采用的解决方案是让一个自定义的桌面应用程序通过直接复制到设备(或存储)来安装移动应用程序和资源文件。应用程序和可选的资源文件都分发在 ZIP 文件中,需要在安装时解压到设备上。这是第一个挑战。

第二个挑战是开发一个更新程序,该程序可以搜索设备上已安装的应用程序和资源文件,并帮助确定要更新哪些组件。顺便说一句,一些已安装的资源文件本身就是 ZIP 文件,其中包含一个包含 ZIP 内容简单描述的文本文件。由于这些文件非常大(超过 2 MB),为了性能原因,将它们全部下载到 PC 以便只提取一个小文件是不可能的——PC 更新程序应该在设备上解压文件并将其复制到 PC。

很长一段时间以来,我一直在使用 Lucian Wischik 在此发布的 Zip Utils,并使用这段代码解决了第一个挑战。在安装过程中,ZIP 文件在 PC 上解压缩到内存缓冲区,然后使用 RAPI 函数调用(如 CeCreateFileCeWriteFile)写入设备。代码有效(已以此方式发布),但我一直觉得如果解压缩在设备上进行而不是在 PC 上进行,速度可能会更快。第一个挑战解决了,但我对结果并不满意:它能运行得更快吗?

解决第二个挑战非常容易,因为代码已经就位。我所要做的就是用 RAPI 等效项替换 ZIP 文件打开和读取函数。为了重用 Lucian 的代码,我选择使用文件指针,当 ZIP 文件位于 PC 上时,这些指针将初始化为常规 API 调用(ReadFileSetFilePointer 等),而当 ZIP 文件位于设备上时,则初始化为 RAPI 的(CeReadFileCeSetFilePointer 等)。无论 ZIP 文件在哪里,您都可以通过此方法高效地解压缩它(请注意,当 ZIP 文件位于设备上时,RAPI 传输的是压缩数据,而不是像从 PC 解压 ZIP 文件到设备时那样传输解压后的数据)。

最后,我必须通过实现 RAPI 扩展 DLL 来解决 PC 到设备的解压缩性能问题。本文介绍了这项工作的成果。

解压场景

本文的代码探索了三种解压场景

  1. 通过常规 RAPI 调用进行的原始 PC 到设备解压缩,正如在原始安装程序代码中所实现的(此处已完全重写)
  2. 使用常规 RAPI 调用进行的设备到 PC 解压缩
  3. 使用专用 RAPI 扩展 DLL 进行的 PC 到设备解压缩

所有这些都包含在附带的命令行应用程序(CeUnzip)中。要使用它,您需要一个通过 ActiveSync(或 Vista 中的 Sync Center)连接到 PC 的 Windows Mobile 设备。该应用程序具有非常简单的命令行格式

CeUnzip -i|-e|-E ZipFileName.zip [TargetDirectory]

这三个选项按如下方式映射到实现的场景

  1. -E:ZIP 文件位于 PC 上,并通过标准 RAPI 函数调用解压缩到设备。
  2. -i:ZIP 文件位于设备上,并通过标准 RAPI 调用解压缩到 PC。
  3. -e:ZIP 文件位于 PC 上,并通过专用 RAPI 扩展 DLL(请参阅包含的源代码中的 CeRemZip 解决方案)解压缩到设备。

当调用 CeUnzip 时,它会报告解压缩整个 ZIP 文件所需的时间(秒),因此比较场景 1 和 3 的结果非常有意义。

在使用 -e 命令行选项之前,您需要确保将包含的 CeRemZip.dll 复制到设备上的 \Windows 目录。此 DLL 是为 Windows Mobile 5 设备(Pocket PC 和 SmartPhone)编译的,在 Windows Mobile 6 设备上运行时也应该无需修改(您也应该可以在 Pocket PC 2003 设备上运行它,但我建议您重新编译以针对该目标)。该 DLL 未签名,因此在首次使用时您会看到可怕的未知发布者警告。

Using the Code

我尽量对 Lucian 的简单界面进行最小的更改。为此,我在 unzip.h 文件中添加了一些函数

ZRESULT CeUnzipItem(HZIP hz, int index, const TCHAR *fn); 

实现了场景 **3** 的解压缩。hz 参数指的是桌面 ZIP 文件,fn 参数指的是设备文件名。

HZIP CeOpenZip(const TCHAR *fn, const char *password);
HZIP CeOpenZipHandle(HANDLE h, const char *password); 

这些函数实现了场景 **2** 的解压缩:ZIP 文件位于设备上。要将文件解压缩到 PC,您可以使用常规的 UnzipItemFindItemGetItem 函数。

场景 **1** 在示例命令行应用程序中明确实现(请参见 ExportUnzip 函数)。ZIP 文件通过原始的解压缩函数调用进行处理,解压缩后的文件通过 CRemoteAPI 类实现的标准 RAPI 调用创建和写入。该类的唯一目的是实现对 RAPI.DLL 的动态链接,从而避免通过版本特定的 RAPI.LIB 进行静态链接。

从示例应用程序中可以看到,初始化和关闭 RAPI 子系统是应用程序的责任。

场景 **2** 由示例应用程序中的 ImportUnzip 函数实现。正如您所看到的,与“正常”解压缩例程唯一的区别在于 ZIP 文件的打开方式:使用 CeOpenZip 而不是 OpenZip

最后,场景 **3** 在 ExportUnzipServer 函数中实现。同样,您看到的唯一相关更改是调用 CeUnzipItem 而不是 UnzipItem

RAPI 扩展

在设备端,场景 **3** 是借助 RAPI 扩展 DLL(示例代码中的 CeRemZip 解决方案)实现的。该扩展实现为流式 RAPI 调用

CEREMZIP_API 
int ZipServer(DWORD        cbInput,
              BYTE*        pInput,
              DWORD*       pcbOutput,
              BYTE**       ppOutput,
              IRAPIStream* pStream)

PC 应用程序仅通过 IRAPIStream 接口与 RAPI 扩展进行通信,发送命令并接收确认。您可以在 unzip.cpp 文件中的一个大...块中看到此代码。

#ifdef RAPI_SERVER

...块。CeRemZip 解决方案必须定义此预处理器常量,但桌面应用程序则不必。

代码的主体在 StreamUnzip 函数中。当 ZipServer 中的执行循环收到解压命令(ZMSG_UNZIP)时,将调用 StreamUnzip 函数,该函数从流中读取一个 RAPIUNZIP 结构(定义在 CeRemZip.h 中),该结构包含有关要创建的文件或目录的所有信息。然后,以 RAPI_BUF_MAX 字节的块读取压缩数据流,并以 FILE_BUF_MAX 字节的块将解压缩后的流写入设备文件。这两个常量对于性能调优非常重要:越大越好(但要注意边际效用递减)。

在桌面端,压缩流在从 ZIP 文件读取后立即发送(请参见 unzip.cpp 中的 unzReadCurrentFile 函数)。为了对 Lucian 的代码进行最少的更改,桌面端也将数据解压缩到本地缓冲区,但将其丢弃。

性能

那么场景 **1** 和 **3** 的性能如何比较呢?我的发现是,场景 **3** 始终比 **1** 快,尽管可能不是显著快。影响 **3** 比 **1** 快的主要因素似乎是 ZIP 压缩率。以下是我的一些发现(时间以秒为单位)

高压缩率 ZIP 文件

Device

场景 1

场景 3

%

i-mate K-Jam

526

106

79.8%

i-mate JasJar

841

245

70.9%

HTC S620

482

75

84.4%

低压缩率 ZIP 文件

Device

场景 1

场景 3

%

i-mate K-Jam

582

539

7.4%

i-mate JasJar

936

767

18.1%

HTC S620

575

523

9.0%

正如您所看到的,场景 **3** 始终更快,但当 ZIP 文件经过高度压缩时,差异才真正具有相关性。

请注意,计时将很大程度上取决于特定设备和存储性能。

历史

  • 2007-08-22:更新了 RapiUnzip.zip 文件
  • 2007-08-21:文章发布
© . All rights reserved.