跳转至

SOUI 项目打包发布指南

本章详细介绍如何将 SOUI 项目打包并发布到目标环境,包括依赖管理、资源打包、部署配置和分发策略等关键步骤。

概述

部署架构

SOUI 应用程序采用模块化架构,部署时需要考虑以下组件:

SOUI 应用程序
├── 核心可执行文件 (YourApp.exe)
├── SOUI 核心库 (soui.dll, utilities.dll)
├── 渲染模块 (render-gdi.dll/render-skia.dll)
├── 图像解码模块 (imgdecoder-stb.dll/imgdecoder-gdip.dll)
├── 应用资源 (uires/ 或 uires.zip)
└── 系统资源 (soui-sys-resource.dll)

部署方式对比

部署方式 优势 劣势 适用场景
绿色部署 无需安装,即拷即用 文件较多,易丢失 便携应用,开发测试
安装包部署 专业化,集成度高 需要安装权限 商业软件发布
单文件部署 文件单一,易分发 启动稍慢,占用内存大 工具类软件

构建准备

构建环境要求

  • Visual Studio 2017+ 或兼容的编译器
  • Windows SDK 10.0+
  • CMake 3.16+(可选)

依赖分析

核心依赖库

# 使用 dumpbin 分析依赖
dumpbin /DEPENDENTS your_app.exe

# SOUI 核心依赖
soui.dll                    # SOUI 核心库
utilities.dll               # 工具库
render-gdi.dll              # GDI 渲染器
imgdecoder-stb.dll          # stb 图像解码器
soui-sys-resource.dll       # 系统资源

# 系统依赖
kernel32.dll, user32.dll, gdi32.dll, ole32.dll

项目配置检查清单

  • 运行时库:设置为 /MT(静态链接)或 /MD(动态链接)
  • 字符集:统一使用 Unicode 字符集
  • 优化级别:Release 版本使用 /O2 优化
  • 调试信息:Release 版本移除调试信息或使用 /Zi
  • 清单文件:包含 DPI 感知和兼容性设置

资源打包

资源组织策略

1. 文件夹部署

YourApp/
├── YourApp.exe
├── soui.dll
├── utilities.dll
├── render-gdi.dll
├── imgdecoder-wic.dll
├── soui-sys-resource.dll
└── uires/
    ├── uires.idx
    ├── xml/
    ├── image/
    └── translation/

优势:资源易于修改和更新,支持热更新 劣势:文件数量多,容易被误删或修改

2. 压缩包部署

SouiFactory souiFactory;
// 使用 ZIP 压缩资源
SAutoRefPtr<IResProvider> pResProvider;
souiFactory.CreateResProvider(RES_ZIP, (IObjRef**)&pResProvider);
if (!pResProvider->Init((LPARAM)_T("uires.zip"), 0))
{
    return FALSE;
}
theApp->AddResProvider(pResProvider);

打包脚本示例

#!/bin/bash
echo "开始打包资源..."
mkdir -p temp_package
cp -r uires/* temp_package/
cd temp_package
zip -r ../uires.zip .
cd .. && rm -rf temp_package
echo "资源打包完成:uires.zip"

3. PE 资源嵌入

// 将资源编译到可执行文件中
SouiFactory souiFactory;
SAutoRefPtr<IResProvider> pResProvider;
souiFactory.CreateResProvider(RES_PE, (IObjRef**)&pResProvider);
if (!pResProvider->Init((WPARAM)GetModuleHandle(NULL), 0))
{
    return FALSE;
}
theApp->AddResProvider(pResProvider);

资源文件配置(.rc 文件):

#include "resource.h"
IDR_RES_ZIP         ZIPRES  DISCARDABLE     "uires.zip"
IDR_LAYOUT_MAIN     XML     DISCARDABLE     "xml\\main.xml"

多语言资源管理

语言包结构

translation/
├── zh-cn.xml              # 简体中文
├── zh-tw.xml              # 繁体中文
├── en-us.xml              # 英语
├── ja-jp.xml              # 日语
└── ko-kr.xml              # 韩语

动态语言切换

class CLanguageManager
{
public:
    static bool LoadLanguage(const SStringT& strLangCode)
    {
        SStringT strLangFile;
        strLangFile.Format(_T("translation\\%s.xml"), strLangCode);

        CAutoRefPtr<IResProvider> pLangRes;
        CreateResProvider(RES_FILE, (IObjRef**)&pLangRes);

        if (pLangRes->Init((LPARAM)strLangFile.c_str(), 0))
        {
            SApplication::getSingleton().AddResProvider(pLangRes);
            return true;
        }
        return false;
    }

    static void SwitchLanguage(const SStringT& strLangCode)
    {
        RemoveCurrentLanguage();
        LoadLanguage(strLangCode);
        RefreshAllWindows();
    }
};

自动化构建

PowerShell 构建脚本

# build-release.ps1
param(
    [string]$Configuration = "Release",
    [string]$Platform = "x64",
    [switch]$Clean
)

$ErrorActionPreference = "Stop"

Write-Host "开始构建 SOUI 项目..." -ForegroundColor Green

# 清理构建
if ($Clean) {
    Remove-Item -Path "build" -Recurse -Force -ErrorAction SilentlyContinue
    Remove-Item -Path "bin" -Recurse -Force -ErrorAction SilentlyContinue
}

# 创建构建目录
New-Item -ItemType Directory -Force -Path "build"
New-Item -ItemType Directory -Force -Path "bin\\$Configuration"

# 构建项目
try {
    & "MSBuild.exe" `
        "YourProject.sln" `
        "/p:Configuration=$Configuration" `
        "/p:Platform=$Platform" `
        "/p:OutDir=..\\bin\\$Configuration\\" `
        "/maxcpucount" `
        "/verbosity:minimal"

    if ($LASTEXITCODE -ne 0) {
        throw "编译失败,退出码:$LASTEXITCODE"
    }
}
catch {
    Write-Error "编译失败:$_"
    exit 1
}

# 复制依赖库
$Dependencies = @(
    "soui.dll",
    "utilities.dll",
    "render-gdi.dll",
    "imgdecoder-wic.dll",
    "soui-sys-resource.dll"
)

foreach ($Dependency in $Dependencies) {
    $SourcePath = "third_party\\soui\\bin\\$Dependency"
    $DestPath = "bin\\$Configuration\\$Dependency"

    if (Test-Path $SourcePath) {
        Copy-Item $SourcePath $DestPath -Force
    }
}

# 打包资源
& ".\\scripts\\package-resources.ps1" -OutputPath "bin\\$Configuration"

Write-Host "构建完成!" -ForegroundColor Green

CMake 构建配置

# CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(SOUIApp VERSION 1.0.0)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 发布配置
if(CMAKE_BUILD_TYPE STREQUAL "Release")
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /O2 /DNDEBUG")
    set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /SUBSYSTEM:WINDOWS")
endif()

# SOUI 库路径
set(SOUI_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/soui)

# 包含和链接目录
include_directories(${SOUI_ROOT}/include/soui)
include_directories(${SOUI_ROOT}/include/utilities)
link_directories(${SOUI_ROOT}/lib)

# 源文件
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h")
add_executable(${PROJECT_NAME} WIN32 ${SOURCES})

# 链接库
target_link_libraries(${PROJECT_NAME}
    soui utilities comctl32 ole32 oleaut32
    uuid kernel32 user32 gdi32
)

# 后构建事件:复制依赖文件
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        "${SOUI_ROOT}/bin/soui.dll"
        "${SOUI_ROOT}/bin/utilities.dll"
        "${SOUI_ROOT}/bin/render-gdi.dll"
        "${SOUI_ROOT}/bin/imgdecoder-wic.dll"
        "${SOUI_ROOT}/bin/soui-sys-resource.dll"
        $<TARGET_FILE_DIR:${PROJECT_NAME}>
)

# 复制资源文件
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${CMAKE_CURRENT_SOURCE_DIR}/uires"
        "$<TARGET_FILE_DIR:${PROJECT_NAME}>/uires"
)

安装包制作

NSIS 安装脚本

; installer.nsi
!include "MUI2.nsh"

Name "SOUI应用程序"
OutFile "SOUIApp_Setup.exe"
InstallDir "$PROGRAMFILES\\SOUIApp"
RequestExecutionLevel admin

; 版本信息
VIProductVersion "1.0.0.0"
VIAddVersionKey "ProductName" "SOUI应用程序"
VIAddVersionKey "FileVersion" "1.0.0.0"

; 现代UI配置
!define MUI_ABORTWARNING
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "license.txt"
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH

!insertmacro MUI_LANGUAGE "SimpChinese"

; 安装文件
Section "核心程序" SecCore
    SectionIn RO

    SetOutPath "$INSTDIR"
    File "bin\\Release\\SOUIApp.exe"
    File "bin\\Release\\soui.dll"
    File "bin\\Release\\utilities.dll"
    File "bin\\Release\\render-gdi.dll"
    File "bin\\Release\\imgdecoder-wic.dll"
    File "bin\\Release\\soui-sys-resource.dll"

    SetOutPath "$INSTDIR\\uires"
    File /r "bin\\Release\\uires\\*.*"

    ; 注册表项
    WriteRegStr HKLM "Software\\SOUIApp" "InstallPath" "$INSTDIR"

    ; 卸载信息
    WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\SOUIApp" "DisplayName" "SOUI应用程序"
    WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\SOUIApp" "UninstallString" "$INSTDIR\\Uninstall.exe"

    WriteUninstaller "$INSTDIR\\Uninstall.exe"
SectionEnd

Section "桌面快捷方式" SecDesktop
    CreateShortCut "$DESKTOP\\SOUI应用程序.lnk" "$INSTDIR\\SOUIApp.exe"
SectionEnd

; 卸载程序
Section "Uninstall"
    Delete "$INSTDIR\\SOUIApp.exe"
    Delete "$INSTDIR\\*.dll"
    RMDir /r "$INSTDIR\\uires"
    Delete "$DESKTOP\\SOUI应用程序.lnk"
    DeleteRegKey HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\SOUIApp"
    DeleteRegKey HKLM "Software\\SOUIApp"
    Delete "$INSTDIR\\Uninstall.exe"
    RMDir "$INSTDIR"
SectionEnd

部署策略

绿色部署

适用场景:便携应用、开发测试、内部工具

部署步骤: 1. 创建应用程序目录 2. 复制所有依赖文件 3. 配置相对路径资源加载 4. 创建启动脚本(可选)

@echo off
REM startup.bat
set APP_DIR=%~dp0
cd /d "%APP_DIR%"
start "" "SOUIApp.exe"

安装包部署

适用场景:商业软件发布、企业级应用

部署特点: - 专业的安装向导 - 系统集成(注册表、开始菜单) - 自动依赖检测和安装 - 完整的卸载功能

单文件部署

适用场景:工具类软件、快速分发

实现方式: 1. 使用资源嵌入技术 2. 静态链接所有依赖 3. 压缩可执行文件

// 单文件部署配置
#pragma comment(linker, "/SUBSYSTEM:WINDOWS")
#pragma comment(lib, "soui_static.lib")
#pragma comment(lib, "utilities_static.lib")

// 嵌入所有资源
#define USE_EMBEDDED_RESOURCES

测试与验证

部署测试清单

  • 干净环境测试:在未安装开发工具的机器上测试
  • 权限测试:在受限用户权限下测试
  • 路径测试:测试中文路径和特殊字符路径
  • 依赖检查:验证所有依赖库都已包含
  • 功能验证:确保所有功能正常工作
  • 多语言测试:验证多语言切换功能
  • 性能测试:检查启动时间和内存占用

自动化测试脚本

# test-deployment.ps1
param([string]$PackagePath)

Write-Host "开始部署测试..." -ForegroundColor Green

# 检查文件完整性
$RequiredFiles = @(
    "SOUIApp.exe",
    "soui.dll",
    "utilities.dll",
    "render-gdi.dll",
    "imgdecoder-wic.dll",
    "soui-sys-resource.dll"
)

foreach ($File in $RequiredFiles) {
    $FilePath = Join-Path $PackagePath $File
    if (Test-Path $FilePath) {
        Write-Host "✅ $File" -ForegroundColor Green
    } else {
        Write-Host "❌ $File 缺失" -ForegroundColor Red
    }
}

# 启动测试
Write-Host "启动应用程序测试..." -ForegroundColor Yellow
$AppPath = Join-Path $PackagePath "SOUIApp.exe"
if (Test-Path $AppPath) {
    $Process = Start-Process $AppPath -PassThru
    Start-Sleep -Seconds 3

    if (!$Process.HasExited) {
        Write-Host "✅ 应用程序启动成功" -ForegroundColor Green
        $Process | Stop-Process -Force
    } else {
        Write-Host "❌ 应用程序启动失败" -ForegroundColor Red
    }
}

最佳实践

版本管理

  1. 语义化版本控制:使用 MAJOR.MINOR.PATCH 格式
  2. 版本信息嵌入:在可执行文件中嵌入版本信息
  3. 自动更新机制:实现增量更新功能

安全考虑

  1. 代码签名:对可执行文件进行数字签名
  2. 完整性检查:使用校验和验证文件完整性
  3. 权限最小化:避免请求不必要的管理员权限

性能优化

  1. 启动优化:延迟加载非关键资源
  2. 内存管理:合理配置静态/动态链接
  3. 文件压缩:使用合适的压缩算法减小体积

总结

SOUI 项目的打包发布需要综合考虑多个方面:

模块化架构:合理组织核心库和应用资源
多种部署方式:根据应用场景选择合适的部署策略
自动化构建:使用脚本和工具提高构建效率
完整性验证:确保部署包的完整性和功能正确性
最佳实践:遵循安全、性能和维护性原则

通过合理的打包策略和自动化流程,可以确保 SOUI 应用程序的稳定部署和高效分发,为用户提供优质的软件体验。