借助网络配置,控制Modbus工具的日志显示,避免卡死界面
智能大石头 authored at 2021-12-11 22:09:19
5.57 KiB
XCoder
# 原生库嵌入与 zip 压缩说明 本文档说明 A1Lib 中原生 DLL 的嵌入方式,以及如何通过 zip 压缩减小程序集体积。 --- ## 一、背景 A1Lib 需要随程序分发若干 ZLG / 创芯 / PEAK 的原生驱动 DLL: | DLL | 用途 | 原始体积 | |---|---|---| | `ControlCAN.dll` | 创芯科技 CAN 卡驱动 | 2.56 MB | | `PCANBasic.dll` | PEAK CAN 卡驱动 | 711 KB | | `zlgcan.dll` | ZLG 致远 CAN 卡驱动(分发层) | 308 KB | | `kerneldlls\*` | ZLG 各设备型号内核驱动 | 39 KB(精简后) | 这些文件是**未压缩的 PE 二进制**,而程序集嵌入资源本身不做压缩, 导致 `A1Lib.dll` 体积偏大。实测 ZIP 压缩率约 **45%**(约 2:1): ``` 合计:3.59 MB -> 1.61 MB(压缩率 45%) ``` 压缩率虽不及 7z(后者可达 3~8 倍),但 **.NET 内置 `System.IO.Compression` 即可解压,无需引入第三方库**,因此优先采用 ZIP。 --- ## 二、工作机制 ### 2.1 嵌入阶段(构建时) `A1Lib.csproj` 采用「**zip 优先,裸文件兜底**」的双条件配置: ```xml <ItemGroup Condition="Exists('CAN\ZLG_CAN\zlgcan.zip')"> <EmbeddedResource Include="CAN\ZLG_CAN\zlgcan.zip" LogicalName="ALib.ZLG_CAN.zlgcan.zip" /> </ItemGroup> <ItemGroup Condition="!Exists('CAN\ZLG_CAN\zlgcan.zip')"> <EmbeddedResource Include="CAN\ZLG_CAN\zlgcan.dll" LogicalName="ALib.ZLG_CAN.zlgcan.dll" /> </ItemGroup> ``` - zip 存在 → 嵌入 zip,体积小 - zip 不存在 → 嵌入原始 DLL,**保证任何情况下都能构建成功** 因此 zip 是**可选优化**,删掉 zip 也能正常编译,只是程序集变大。 ### 2.2 释放阶段(运行时) 首次使用某个原生库时自动解压还原到程序目录: ``` ZipResourceExtractor.ExtractFile() 单文件:{前缀}.{名去扩展名}.zip ZipResourceExtractor.ExtractToDirectory() 目录 :{前缀}.{目录名}.zip ↑ DllResourceManager.ExtractDllFromResource() 按「zip 优先」选择资源 KernelDllExtractor.Extract() kerneldlls 目录 ``` **资源名约定**(必须与 csproj 的 `LogicalName` 一致): | 形态 | 约定 | 示例 | |---|---|---| | 单文件 | `{前缀}.{文件名去扩展名}.zip` | `ALib.ZLG_CAN.zlgcan.zip` | | 目录 | `{前缀}.{目录名}.zip` | `ALib.ZLG_CAN.kerneldlls.zip` | --- ## 三、如何生成 zip 在 `A1Lib` 目录下执行打包脚本: ```powershell .\pack_native_res.ps1 ``` 脚本会为每个目标生成同名 zip 并输出压缩统计: ``` 目标 类型 文件数 原始 压缩后 压缩率 CAN\ZLG_CAN\zlgcan.dll file 1 307.5 KB 129.8 KB 42% CAN\ZLG_CAN\kerneldlls dir 3 38.8 KB 17.9 KB 46% CAN\CX_CAN\ControlCAN.dll file 1 2.56 MB 1.16 MB 45% CAN\PCAN\PCANBasic.dll file 1 711.1 KB 310.2 KB 44% 合计:3.59 MB -> 1.61 MB(压缩率 45%) ``` 仅打包单个目标: ```powershell .\pack_native_res.ps1 -Target 'CAN\ZLG_CAN\kerneldlls' ``` > **注意**:脚本含中文输出,文件必须保存为 **UTF-8 with BOM**, > 否则 Windows PowerShell 5.1 会按 ANSI 解析而报语法错误。 --- ## 四、注意事项 ### 4.1 原始文件保留,不参与编译 zip 与原始 DLL 同时存在于源码目录: ``` CAN/ZLG_CAN/ ├── zlgcan.dll ← 保留:供打包、排查使用 ├── zlgcan.zip ← 嵌入:实际随程序集发布 └── kerneldlls/ ← 保留:供打包、排查使用 ``` csproj 通过 `Condition` 只嵌入其中之一,两者不会重复打包。 ### 4.2 zip 内的目录结构 - **单文件 zip**:zip 内直接是该文件(`zlgcan.dll`) - **目录 zip**:以**目录内容为根**,不含目录名本身 (即 `kerneldlls.zip` 内的条目是 `USBCAN.dll`、`dll_cfg.ini` 等, 而非 `kerneldlls/USBCAN.dll`),解压后直接铺到目标目录下。 这样 `kerneldlls\` 的相对路径才能被 `zlgcan.dll` 正确找到。 ### 4.3 安全与健壮性 解压实现已考虑以下情况: | 场景 | 处理 | |---|---| | zip 条目含 `..\` 路径穿越 | 校验目标路径必须落在解压目录内,否则跳过 | | 文件已存在且大小一致 | 跳过写入,减少磁盘操作 | | 目标文件被占用(驱动已加载) | 保留旧文件不报错,不影响使用 | | 解压中断导致目录不完整 | `kerneldlls` 用 `dll_cfg.ini` 作完整性标记,缺失则重新解压 | | 未打包 zip | 自动回退嵌入裸文件,功能不受影响 | ### 4.4 更换设备型号后需重新打包 若从 `ZLG_USBCAN/kerneldlls_original/` 取回了新的驱动文件, **必须重新运行打包脚本**,否则 zip 内仍是旧内容。 --- ## 五、后续可改进项 - **7z 支持**:7z 压缩率显著优于 ZIP(实测 kerneldlls 7.2MB → 932KB), 但需引入 `SevenZipSharp` / `SharpCompress` 等第三方库, 或改为调用外部 `7z.exe`。当前方案已用 ZIP 覆盖主要收益。 - **增量打包**:目前每次全量重打包,可按文件时间戳跳过未变更项。 - **构建时自动打包**:可加 MSBuild Target 在 `BeforeBuild` 自动调用脚本, 省去手动执行(代价是每次构建增加压缩耗时)。 --- ## 六、相关文件 | 文件 | 职责 | |---|---| | `pack_native_res.ps1` | 打包脚本:生成各原生库的 zip | | `ZipResourceExtractor.cs` | 通用 zip 资源释放(单文件 / 目录两种模式) | | `DllResourceManager.cs` | 单个 DLL 的「zip 优先」释放与加载 | | `CAN/ZLG_CAN/KernelDllExtractor.cs` | kerneldlls 目录的释放(zip 优先,逐个兜底) | | `A1Lib.csproj` | 嵌入配置(zip 优先、裸文件兜底) |