资讯动态

NSIS+Duilib 仿聊天软件安装包:源码解析与二次开发指南

发布时间:2026/10/16 9:31:17 来源:尧图企业网站定制
简介这是一份面向Windows桌面开发者的NSIS与Duilib整合实战工程目标是复刻腾讯QQ安装程序的界面风格与交互流程适合已具备C基础、希望掌握自定义安装包制作的开发者参考。压缩包共206个文件约69.53MB以h头文件与cpp源码为主体配合obj、pdb等编译中间产物另有png界面素材、sln与vcxproj工程文件、nsi与nsh脚本、dll插件及7z、rar压缩组件覆盖从界面渲染到安装逻辑的完整链路。工程按3party、samples、plugin、include等目录组织分别承载第三方库、示例模板、NSIS扩展插件与公共头文件便于按模块研读。目前已有1866人学习下载。通过该工程可掌握Duilib界面元素与NSIS脚本的协同方式理解安装流程定制、插件调用与资源打包思路并借鉴仿QQ风格界面的实现细节对提升桌面安装程序开发能力具有实际参考价值。1. 从一次安装包改造说起NSIS 搭 Duilib 到底能做出什么前阵子帮朋友改一个桌面工具的安装程序需求很具体安装界面要像主流聊天软件那样左侧导航、右侧内容区、顶部品牌图、底部按钮还要支持自定义安装路径、组件勾选、静默安装。他一开始想用 Electron 套壳被我劝住了——一个安装包动辄上百兆用户下载完还没装就先骂街。后来翻出一套老方案NSIS 负责安装逻辑Duilib 负责界面渲染两者拼起来安装包体积能压在几兆以内界面还能做得像模像样。这套「NSISDuilib 仿某聊天软件安装包」的源码核心价值就在这儿它把 NSIS 的脚本能力和 Duilib 的 DirectUI 渲染接在一起让你不用重写安装引擎只改 XML 布局和脚本逻辑就能产出一个带现代 UI 的 Windows 安装程序。适合两类人一是需要给自家桌面软件做定制安装界面的开发者二是想学 NSIS 插件通信和 Duilib 窗口嵌入的 Windows 客户端方向同学。下面按「能干什么 → 怎么跑 → 怎么改」的顺序拆一遍。2. 架构拆解NSIS 脚本层与 Duilib 渲染层怎么握手2.1 两层结构谁负责逻辑谁负责画界面这套源码的分工很清晰。NSIS 侧是宿主负责安装流程控制解压文件、写注册表、创建快捷方式、处理静默参数。Duilib 侧是一个独立的 DLL 或内嵌窗口负责把安装界面画出来接收鼠标点击、勾选、路径输入这些交互再把结果回传给 NSIS。两者之间的通信靠 NSIS 插件机制。常见做法是写一个nsDuilib.dll导出几个函数给 NSIS 脚本调用比如ShowInstallWizard、GetInstallPath、GetSelectedComponents。NSIS 脚本在.onInit里调用ShowInstallWizardDuilib 窗口起来后进入自己的消息循环用户点「开始安装」时窗口把收集到的参数写进一块共享内存或临时文件然后关闭自己NSIS 继续往下走安装流程。这种「NSIS 主控 Duilib 子窗口」的模式好处是安装逻辑不用动界面可以随便换。坏处是调试麻烦——Duilib 窗口崩了NSIS 那边只能看到一个插件调用失败得靠日志和 OutputDebugString 慢慢排。2.2 目录结构拿到源码先看哪几个文件源码包解压后目录大致是这样NSISDuilibInstaller/ ├── nsis/ │ ├── installer.nsi # 主安装脚本 │ ├── pages/ # 各安装页面的 NSIS 宏 │ └── plugins/ # 编译好的 nsDuilib.dll ├── duilib/ │ ├── UI/ # Duilib 窗口类实现 │ │ ├── InstallWizard.h/cpp │ │ └── PageBase.h/cpp │ ├── res/ # XML 布局和图片资源 │ │ ├── wizard.xml │ │ └── skin/ │ └── third_party/duilib/ # Duilib 库源码 ├── build/ │ ├── build_duilib.bat # 编译 Duilib 插件 │ └── build_installer.bat # 编译 NSIS 安装包 └── output/ └── Setup.exe # 最终产物先看installer.nsi它决定了安装流程有几步、每步干什么。再看duilib/UI/InstallWizard.cpp这是界面主窗口的入口。res/wizard.xml是布局文件改界面基本都在这里动。build_duilib.bat和build_installer.bat是编译脚本跑通它们比手动敲命令靠谱。2.3 关键通信参数怎么从界面传到脚本Duilib 窗口收集到的安装路径、组件勾选状态需要传给 NSIS。源码里用的是临时文件方案简单直接// duilib/UI/InstallWizard.cpp void CInstallWizard::OnClickStartInstall(TNotifyUI msg) { // 收集界面上的参数 std::wstring installPath m_pPathEdit-GetText(); bool createDesktopShortcut m_pDesktopCheck-IsSelected(); bool installComponentA m_pCompACheck-IsSelected(); // 写入临时文件NSIS 侧读取 std::wstring tempFile GetTempFilePath(Lnsis_install_params.ini); WritePrivateProfileString(LInstall, LPath, installPath.c_str(), tempFile.c_str()); WritePrivateProfileString(LInstall, LDesktopShortcut, createDesktopShortcut ? L1 : L0, tempFile.c_str()); WritePrivateProfileString(LInstall, LComponentA, installComponentA ? L1 : L0, tempFile.c_str()); // 通知 NSIS 可以继续 Close(); }NSIS 侧对应读取; nsis/installer.nsi Function ReadInstallParams ReadINIStr $INSTDIR $TEMP\nsis_install_params.ini Install Path ReadINIStr $0 $TEMP\nsis_install_params.ini Install DesktopShortcut StrCmp $0 1 0 2 CreateShortCut $DESKTOP\MyApp.lnk $INSTDIR\MyApp.exe FunctionEnd这里用 INI 文件而不是共享内存是因为 NSIS 脚本操作文件比操作内存指针方便而且调试时能直接打开临时文件看参数对不对。注意临时文件路径要带进程 ID 或随机后缀避免多实例冲突。源码里GetTempFilePath做了这个处理改的时候别把它去掉。3. 跑起来从编译 Duilib 插件到生成 Setup.exe3.1 环境准备VS 版本和 NSIS 版本要对上这套源码对编译环境有要求。Duilib 部分需要 Visual Studio 2015 及以上因为用到了 C11 的一些特性。NSIS 建议用 3.06 以上版本老版本对 Unicode 支持不完整中文路径会出问题。安装 NSIS 后把nsis/plugins/nsDuilib.dll放到 NSIS 安装目录的Plugins文件夹下或者放在脚本同级的plugins目录里编译时用!addplugindir指定。源码里的build_installer.bat已经写了这个路径直接跑就行。注意如果你机器上装了多个 VS 版本build_duilib.bat里调msbuild时最好写全路径否则可能调到旧版本导致编译失败。3.2 编译 Duilib 插件先解决依赖再谈界面打开build_duilib.bat核心命令是:: build/build_duilib.bat call C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat x86 msbuild duilib\UI\UI.vcxproj /p:ConfigurationRelease /p:PlatformWin32 copy /Y duilib\UI\Release\nsDuilib.dll nsis\plugins\这里编译的是UI.vcxproj输出nsDuilib.dll。如果编译报错找不到duilib.h检查third_party/duilib目录是否完整以及项目属性里的附加包含目录有没有指对。常见做法是把 Duilib 编译成静态库再链接进 DLL这样发布时不用带额外的 dll源码里也是这么做的。编译成功后用dumpbin /exports nsDuilib.dll看一下导出的函数名确认ShowInstallWizard这些函数在。如果不在检查.def文件或extern C声明。3.3 编译安装包NSIS 脚本里的几个关键宏build_installer.bat调用makensis.exe:: build/build_installer.bat makensis /DVERSION1.0.0 /DOUTPUT_DIR..\output nsis\installer.nsiinstaller.nsi里几个宏决定了安装包行为; 定义安装包基本信息 !define PRODUCT_NAME MyApp !define PRODUCT_VERSION 1.0.0 !define PRODUCT_PUBLISHER MyCompany ; 引入 Duilib 插件 !addplugindir /x86-unicode plugins ; 安装页面调用 Duilib 窗口 Page custom ShowDuilibPage Function ShowDuilibPage nsDuilib::ShowInstallWizard Pop $0 StrCmp $0 success 0 2 Abort ; 用户取消中止安装 FunctionEndPage custom定义了一个自定义页面ShowDuilibPage里调用插件。插件返回success表示用户点了开始安装返回其他值就Abort中止。这里有个细节Duilib 窗口关闭后NSIS 的页面栈需要正确处理否则会出现页面卡住或重复弹出的问题。源码里在ShowInstallWizard返回后加了一个Abort判断改的时候注意保留。编译完成后output/Setup.exe就是最终产物。双击跑一遍看界面是否正常、安装路径是否生效、快捷方式是否创建。3.4 验证安装结果别只看界面要查注册表和文件安装完成后按WinR输入regedit定位到HKEY_LOCAL_MACHINE\SOFTWARE\MyApp看版本号和安装路径写对没有。再去安装目录看文件是否完整桌面快捷方式是否能启动程序。如果界面显示成功但注册表没写多半是 NSIS 脚本里WriteRegStr的路径变量用错了检查$INSTDIR是否被 Duilib 传回的路径覆盖。4. 改界面和逻辑XML 布局、脚本分支、插件扩展4.1 改 XML 布局换图、调尺寸、加控件Duilib 的界面全在res/wizard.xml里。想换顶部品牌图找到Control namebrand_image改bkimage属性指向新图片。想调窗口大小改根节点的width和height。想加一个「同意协议」勾选框在对应容器里加CheckBox nameagree_check text我已阅读并同意协议 textcolor#FF333333 selectedfalse margin20,10,0,0/然后在InstallWizard.cpp里给这个控件绑定变量在OnClickStartInstall里判断是否勾选。注意 XML 里的name要和代码里FindControl用的名字一致大小写敏感。4.2 改安装逻辑在 NSIS 脚本里加分支比如要加一个「安装为服务」的选项先在 Duilib 界面加勾选框把状态写进 INI 文件然后在 NSIS 脚本里读ReadINIStr $0 $TEMP\nsis_install_params.ini Install AsService StrCmp $0 1 0 skip_service ExecWait $INSTDIR\MyApp.exe --install-service skip_service:如果服务安装失败可以用IfErrors跳转到错误提示页面。NSIS 的错误处理比较原始建议每个关键步骤后都加日志输出方便排查。4.3 扩展插件加一个新页面或新功能想加一个「选择安装语言」的页面可以在 Duilib 里新建一个LanguagePage类继承PageBase实现OnInit和OnClickNext。然后在InstallWizard里把它加入页面列表用SwitchPage切换。NSIS 侧不需要改因为所有页面都在 Duilib 窗口内部管理只有最终参数通过 INI 文件传出。这种设计的好处是 NSIS 脚本保持简洁界面逻辑全在 C 侧。坏处是每次改界面都要重新编译 DLL不能像纯 NSIS 脚本那样改完直接编译安装包。如果界面改动频繁可以考虑把部分简单页面用 NSIS 原生控件实现复杂页面再用 Duilib。5. 避坑记录编译、运行、打包时最容易翻车的几个点5.1 现象编译 Duilib 时报「无法打开包括文件 duilib.h」原因third_party/duilib目录不完整或者项目属性里的附加包含目录路径写的是绝对路径换机器就失效。解决检查duilib/UI/UI.vcxproj里的AdditionalIncludeDirectories改成相对路径$(ProjectDir)..\third_party\duilib。如果目录确实缺文件从 Duilib 官方仓库拉一份完整源码放进去。5.2 现象安装包运行后界面不显示直接跳过原因nsDuilib.dll没有放到 NSIS 能找到的目录或者!addplugindir路径写错。NSIS 插件加载失败时默认不报错直接跳过自定义页面。解决在installer.nsi开头加!echo Plugin dir: ${NSISDIR}\Plugins编译时看输出路径对不对。也可以把 dll 直接放到nsis/plugins/下用!addplugindir /x86-unicode plugins指定相对路径。5.3 现象中文路径安装后程序启动报错原因NSIS 脚本里用了 ANSI 版本的字符串操作或者 Duilib 写 INI 文件时用了WritePrivateProfileStringA。解决统一用 Unicode 版本。NSIS 编译时加/DUNICODEDuilib 侧用WritePrivateProfileStringW。源码里已经是 Unicode 版本改的时候别混用 A 版本函数。5.4 现象用户取消安装后NSIS 仍然继续执行原因ShowInstallWizard返回后没有正确Abort或者返回值判断逻辑写反了。解决在ShowDuilibPage里加日志输出返回值确认Pop $0拿到的是什么。常见做法是插件返回cancel时调用Abort返回success时继续。源码里用的是StrCmp $0 success 0 2意思是如果等于 success 就跳过 Abort否则执行 Abort。改的时候注意这个逻辑。5.5 现象安装包体积异常大原因Duilib 编译时带了调试符号或者资源文件里塞了太多高清图。解决Release 编译时关掉调试信息图片用压缩过的 PNG 或 JPG。常见做法是把品牌图控制在 200KB 以内背景图用纯色或渐变代替大图。源码里res/skin/下的图片已经压缩过替换时注意别直接扔原图进去。6. 二次开发把安装包改成自家产品的几个实用改法拿到这套源码最直接的改法是换品牌资源。把res/skin/下的 logo、背景图、图标全换成自己的改wizard.xml里的文字和颜色半小时就能出一个看起来完全不同的安装界面。但真正要落地到自家产品还得动几个地方。第一安装流程要跟自家程序对齐。比如你的程序需要装 VC 运行库就在 NSIS 脚本里加ExecWait调用vcredist_x86.exe装完再继续。如果运行库已经装了用IfFileExists判断一下跳过。这种依赖检查建议放在 Duilib 界面之前避免用户填完路径才报错。第二静默安装参数要支持。很多企业部署场景要求/S静默安装这时候不能弹 Duilib 窗口。在installer.nsi里判断IfSilent silent_install ; 正常模式显示 Duilib 界面 Page custom ShowDuilibPage Goto done silent_install: ; 静默模式用默认路径和默认组件 StrCpy $INSTDIR $PROGRAMFILES\MyApp done:静默模式下 Duilib 不启动所有参数用默认值。测试时用Setup.exe /S跑一遍确认文件正确释放、注册表正确写入。第三卸载逻辑要跟安装逻辑对称。NSIS 的卸载程序默认会删安装目录但如果你的程序在AppData或注册表里写了东西得在un.onInit里手动清理。常见做法是安装时把写过的路径记到一个日志文件里卸载时按日志删。源码里uninstaller.nsi有基础框架改的时候注意别漏掉自定义的注册表项。第四界面风格要跟主程序统一。如果主程序是深色主题Duilib 的 XML 里把背景色、文字色、按钮样式全调一遍。Duilib 支持皮肤文件可以把颜色定义抽到skin.xml里换主题时只改一个文件。源码里没做皮肤切换但结构上留了扩展空间加一个LoadSkin函数按配置加载不同 XML 就行。最后说一个我踩过的坑改完 XML 后忘了重新编译 DLL直接编译 NSIS 脚本结果安装包里的界面还是旧的。后来养成习惯每次改完res/下的文件先跑build_duilib.bat再跑build_installer.bat两步都成功才去测安装包。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑