☰
海康威视SDK客户端安装包制作实战:从依赖梳理到Inno Setup打包
2026/10/17 12:59:24 网站建设 项目流程

作海康威视SDK二次开发的,最烦的往往不是写业务代码,而是最后收尾那一下——把程序打包成安装包。开发机上跑得好好的,换到客户电脑上就各种缺DLL、连不上设备、配置文件找不到。我自己前后折腾过不少次,从最早的WinForm项目,到后来整体切到WPF客户端,中间踩过的坑足够写一篇长文了。这篇文章就是把我在WPF/WinForm客户端对接海康威视SDK时,制作安装包的完整思路和实操过程整理出来,给正准备收尾上线的朋友做个参考。

1. 打包之前,先把项目结构理清楚

很多人一上来就找打包工具,其实在动手之前,最该做的是把“要打进安装包的东西”分门别类列清楚。海康威视客户端和普通业务软件不太一样,它除了你自己的exe和DLL,还牵扯到海康的SDK运行库、视频组件、配置文件,弄混一个就要出问题。

1.1 明确程序集和SDK依赖的边界

先看一张粗粒度清单,你项目里多半有这些文件:

  • 你自己的主程序exe,以及随项目生成的所有业务DLL
  • 第三方控件的运行库(比如图表、UI框架之类的)
  • 数据库相关文件,包括数据库引擎、配置文件
  • 海康威视的SDK运行库,包含HCNetSDK.dll、PlayCtrl.dll等播放库,以及它们附带的一些底层DLL
  • 配置文件,比如App.config、连接字符串、设备参数配置
  • 运行环境,一般指.NET Framework对应版本或者.NET 8运行时

我实际在做项目的时候,会单独建一个“部署清单”的Excel表格,每一类文件都注明来源目录、目标安装目录、是否可选组件。别嫌麻烦,后期排查问题全靠它。

1.2 32位和64位架构,必须提前定死

海康SDK的DLL分x86和x64两种,这个事在打包时是第一个要确认的。很多同事在这上面吃过亏:程序编译的是AnyCPU,到客户机器上运行到SDK初始化就报错,查半天发现是DLL架构不匹配。

我个人的建议是:尽量统一编译目标。

  • 如果客户环境是老旧的Windows 7 32位系统,那整个程序编译成x86,SDK也放x86版本
  • 如果客户环境是64位系统,并且有内存占用较大的需求,那就编译为x64,SDK放x64版本
  • 尽量避免AnyCPU,海康SDK加载时会找当前进程架构对应的DLL,AnyCPU在这种场景下反而容易出问题

还有一点,海康的SDK里有个HCNetSDK.dll,它的加载依赖一些Visual C++运行库。打包的时候别漏掉,不然客户电脑上会报“找不到MSVCR100.dll”之类的错误。

1.3 配置文件的位置和内容,先规划再打包

对于WPF程序,通常会有App.config文件,编译之后变成“程序名.exe.config”。WinForm也是类似。配置文件的处理重点在于:哪些配置项是机器相关的,哪些是全局固定的。

机器相关的配置项,比如数据库连接字符串、设备IP端口、录像存储路径,这些不应该在打包时写死,而应该在安装过程中或者程序首次运行时生成。我习惯的做法是:打包时只带一份默认配置文件,安装完成后程序首次启动时检查配置完整性,缺了就让用户填,或者从安装目录下的“配置模板”目录读取。

这样有个明显的好处:换一台电脑,安装包不用重新做,客户改配置文件或者通过界面设置就能适配新环境。

2. 安装工具怎么选,我为什么最后固定用Inno Setup

打包工具圈子里常用的无非就是那几样:Visual Studio自带的InstallShield、Advanced Installer、Inno Setup、NSIS,还有早期的Wix。我不打算一个个全讲,只说大家最常用的对比,以及为什么我最后在项目里固定下了Inno Setup。

2.1 几种主流安装工具的真实使用感受

工具优点缺点适合场景
InstallShield集成在VS里,上手门槛低脚本逻辑受限,体积大简单项目、一次性打包
Advanced Installer图形化操作好,支持多语言界面高级功能收费,许可证费用不低需要漂亮安装界面的商业软件
Inno Setup免费、脚本可控、安装包体积小初始学习曲线偏陡项目经常更新、需要批量打包
NSIS脚本插件生态强,性能高需要自己写大量脚本有定制化安装需求的极客型项目

我一开始图省事用的InstallShield,但项目进入稳定迭代期后,每两周就要发一次版本,InstallShield那个图形化配置反复改起来特别费劲,后来干脆把整个打包脚本用Inno Setup重新写了一遍。现在项目里不管WPF还是WinForm客户端,全部用Inno Setup出包,一条命令行就能打出新版本安装包,效率翻了好几倍。

2.2 为什么海康项目推荐Inno Setup

海康二次开发项目有个特点:依赖文件多,而且SDK的DLL可能随着版本更新而变化。Inno Setup的脚本式管理正好契合这个场景——文件列表、注册表项、快捷方式、卸载逻辑全部用文本维护,改起来就是直接编辑脚本,不用在图形界面里点来点去。

另外一个关键点是:Inno Setup对运行库检测和可选组件的控制非常灵活。比如我可以在脚本里判断系统是否装了对应版本的.NET Framework,没装就自动帮你引入离线安装包,装完主程序再继续。这个流程在InstallShield里也能做,但没有Inno Setup脚本这么直白。

3. 正式打包前,需要准备好的资源和环境

写Inno Setup脚本之前,有几样东西得提前准备好,不然写脚本的过程中会被卡住。

3.1 收集海康SDK的完整文件清单

海康威视的SDK压缩包解压后,一般能看到几个子目录:

  • 库文件目录,包含HCNetSDK.dll、GdiPlus相关、音频库等
  • PlayCtrl播放器库,用于预览和回放
  • 依赖库目录,比如HCCore相关的DLL
  • 示例代码和头文件,这个不需要打包

打包时只需要把运行所需的DLL拷贝进安装包。具体需要哪些,有个笨办法:先把DLL全部放进去,装到干净的虚拟机里跑一遍,如果发现某个DLL根本没被用到,再从清单里移除。如果被裁剪了,就用Dependency Walker或者Process Explorer看加载链,缺哪个补哪个。我实际测试下来,海康SDK里有一部分是软依赖,就是只在特定功能下才调用,比如语音对讲,这部分DLL建议不管用不用都保留,反正体积不大,省得出稀奇古怪的问题。

3.2 准备.NET运行时和VC运行库

现在有些客户机器是干净的,什么运行库都没有。安装包里最好把以下内容作为前置安装组件:

  • .NET Framework 4.8(如果程序目标框架是.NET Framework)
  • .NET 8 Desktop Runtime(如果程序目标是.NET 8)
  • Visual C++ 2015-2022 Redistributable(x86和x64都带上)
  • 如果是64位程序,VC运行库的x64版本必须装

有一种更稳妥的做法:在打包时把运行库的离线安装包放到安装包的某个子目录,然后在Inno Setup脚本里写安装顺序,先装运行库,再装主程序。注意顺序装错,比如主程序装完才装运行库,某些系统上会要求重启后才生效,体验很差。

3.3 程序本身做一次“绿色发布”验证

正式做安装包之前,我每次都先把编译输出的整个目录拷贝到另一台干净机器上,直接运行exe,看看能不能跑起来。这个过程叫“绿色验证”。如果这都跑不起来,那问题大概率不在打包上,而在程序本身的依赖配置上,先回去改代码比改打包脚本更快。

绿色验证时重点看:

  • 程序目录是不是全部文件都在(有没有漏拷贝的DLL)
  • 配置文件的相对路径是否能被正确读取
  • 数据库能不能连上(如果本地要装数据库引擎的话)
  • 海康SDK是否能正常初始化设备列表

这些在开发机器上都通过之后,我才会开始写打包脚本。

4. Inno Setup脚本的完整拆解与写法

我直接用一段实际项目的关键脚本来做说明。这个项目是WPF客户端,目标框架是.NET Framework 4.8,海康SDK用的是x64版本。

4.1 Inno Setup脚本的基本框架

; 脚本使用Inno Setup 6.x编写 [Setup] AppName=海康视频监控客户端 AppVersion=1.2.0 AppPublisher=内部项目组 AppPublisherURL=http://内部地址 DefaultDirName={pf}\HikClient DefaultGroupName=海康视频监控客户端 OutputDir=.\InstallPack OutputBaseFilename=HikClient_Setup_1.2.0_x64 Compression=lzma2/max SolidCompression=yes ArchitecturesAllowed=x64compatible ArchitecturesInstallIn64BitMode=x64compatible PrivilegesRequired=admin ; 这个选项很关键,决定是否生成64位安装包 [Languages] Name: "chinesesimp"; MessagesFile: "compiler:Default.isl" [Run] ; 先装VC运行库,再装.NET Framework Filename: "{tmp}\vcredist_x64.exe"; Parameters: "/install /quiet /norestart"; Check: NotVCInstalled; Flags: waituntilterminated Filename: "{tmp}\NDP48-x86-x64-AllOS-ENU.exe"; Parameters: "/quiet /norestart"; Check: NotDotNetInstalled; Flags: waituntilterminated [Files] Source: "..\bin\x64\*"; DestDir: "{app}"; Flags: recursesubdirs createallsubdirs ; 把运行库离线包拷到临时目录 Source: "..\redist\vcredist_x64.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall Source: "..\redist\NDP48-x86-x64-AllOS-ENU.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall [Icons] Name: "{group}\海康视频监控客户端"; Filename: "{app}\HikClient.exe" Name: "{commondesktop}\海康视频监控客户端"; Filename: "{app}\HikClient.exe"

这段脚本里,有几个细节我提醒一下:

  • ArchitecturesInstallIn64BitMode=x64compatible是Inno Setup 6.3以后的写法,表示安装包本身可以在64位系统上执行,并且安装到64位目录。老版本直接写ArchitecturesInstallIn64BitMode=x64
  • [Files]段用recursesubdirs把整个bin目录递归打进包,比你手动列几百个DLL靠谱得多
  • {tmp}目录下的运行库安装完就删除,避免给客户电脑留垃圾文件

4.2 判断系统缺不缺运行库

上面脚本里我写了两个检查函数,这里具体展开。

[Code] function NotVCInstalled(): Boolean; begin // 检查注册表里是否已经存在VC运行库条目 Result := not RegKeyExists(HKLM, 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64'); end; function NotDotNetInstalled(): Boolean; var version: Cardinal; begin // 检查.NET Framework 4.8的版本号,528040表示安装了4.8 Result := True; if RegQueryDWordValue(HKLM, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full', 'Release', version) then begin if version >= 528040 then Result := False; end; end;

这套做法的核心思路是:安装前先检查,缺了才安装,不缺就跳过。有些安装包不管三七二十一强制装运行库,遇到已经装了更高版本的系统,往往需要重启,客户体验很差。用检查函数做前置判断,能省掉大量不必要的麻烦。

4.3 安装完成后的卸载逻辑和日志

安装包还有一块常被忽视的地方是卸载。海康客户端通常会有日志文件、临时文件、设备注册信息,卸载时不清理干净,重装的时候容易出问题。

我在脚本里加了卸载时删除日志和配置的步骤:

[UninstallDelete] Type: filesandordirs; Name: "{app}\Logs" Type: filesandordirs; Name: "{app}\DeviceCache" Type: files; Name: "{userappdata}\HikClient\config.ini"

清理日志这个操作要慎重,如果客户有保存录像和配置文件在程序目录之外的需求,不要一股脑全删。最好是拆成两部分:程序目录下的缓存和运行日志可删,客户主动保存的数据(比如录像导出目录)不动。

5. 把海康SDK的坑提前填平

讲完通用打包流程,这一节专门说海康SDK和安装包之间的那些“微妙关系”。这些内容你在官方SDK文档里基本看不到,全是实际部署中被坑过才总结出来的。

5.1 SDK初始化失败的头号原因:DLL搜索路径

WPF程序的默认DLL搜索路径是程序所在目录、系统目录、系统PATH。海康的HCNetSDK.dll在加载PlayCtrl.dll、HCCore等库的时候,也是先从自己的模块路径下找。正常情况下,只要所有SDK DLL都放在程序目录下,是不需要额外设置搜索路径的。

但有一种特殊情况:如果你把SDK DLL放在子目录,比如{app}\SDK下,然后调用HCNetSDK初始化,就会出现明明DLL都在却加载不了的情况。

解决办法有两个方向:

  • 简单粗暴:所有DLL平铺在程序根目录,包括SDK的
  • 结构清晰:SDK放在子目录,同时在程序启动时调用SetDllDirectory或AddDllDirectory指定搜索路径

我自己的项目为了管理方便,选择了后一种。在程序入口处加上一行:

[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] private static extern bool SetDllDirectory(string lpPathName); // 在Main函数最开始调用 SetDllDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SDK"));

这里有个顺序问题:先设定目录,再去调用海康SDK的初始化接口。如果是WPF项目,建议在Application启动事件里处理,或者在Main方法的早期。别等到窗体加载完才搞,太晚了。

5.2 多个DLL版本冲突怎么处理

海康SDK在某个版本之后,依赖的第三方DLL(比如音频相关的)越来越多,而且有些DLL和第三方控件引用的版本不一致。最容易出现的是“ollvm.dll版本冲突”,实际项目中遇到过不止一次。

处理方法说穿了很简单:

  • 把SDK运行库单独放到子目录,与主程序自己的DLL隔离
  • 主程序和SDK各自用自己目录下的全部依赖,不共享
  • 如果两个DLL名字一样但版本不同,不要强行合并,只能用目录隔离

这种方法唯一的代价是稍微占用一点磁盘空间,但能换来很大的稳定性。打包时在[Files]段里单独加一行,把SDK目录拷到{app}\SDK下,和主程序分离即可。

5.3 海康SDK的初始化参数文件

海康的SDK初始化时,有些功能(比如设备能力集)、部分接口依赖一个参数文件或者日志目录。官方SDK有接口可以指定日志保存路径,这个路径在部署时必须保证存在且有写权限。

我之前遇到过一个情况:程序安装在Program Files目录下,SDK初始化后需要写日志,而客户是标准用户权限,没有对Program Files的写入权限,日志就写不进去,导致SDK某些功能不可用。最典型的是设备搜索功能偶尔没反应,查了半天发现是日志路径权限问题。

现在我的做法是:

  • 把SDK的日志目录设置在{localappdata}\HikClientLog
  • 在安装脚本里预先创建好这个目录
  • 如果目录创建失败,程序启动时也会自动尝试创建,并给出对应提示

配置文件的路径同理,原则上不写入Program Files下的程序目录,而写入{userappdata}或者{commonappdata}。这样能兼容各种权限模式,基本不会再出现客户环境跑不动的情况。

6. WinForm和WPF在打包上的区别

做海康客户端的时候,老项目基本是WinForm,新项目大多切到WPF。两种框架在打包时的关注点其实有区别,这里单独拿出来说。

6.1 WinForm打包相对简单的点

WinForm项目整体上依赖比较直接,程序集少,运行时对系统资源的感知也简单。打包时注意:

  • 数据库连接如果用的是本地SQLite,注意把SQLite的混合模式DLL放对位置
  • 如果用了第三方UI控件(比如皮肤控件),一定要确认对应版本,有些皮肤DLL和主程序版本不匹配会导致直接崩溃
  • WinForm的配置文件相对简易,连接字符串、设备参数基本都在App.config里,打不打包问题不大

WinForm打包时最容易出错的是自动升级功能。很多老项目有自己的升级器,升级器在安装包里必须放在主程序的同级目录,不能放到别的子目录,否则升级逻辑找不到路径就罢工。

6.2 WPF打包要注意的细节

WPF项目打包时要留意的地方明显更多:

  • WPF程序可能有资源文件(图片、字体、样式字典),这些是嵌入资源,不打进安装包没关系,但如果是Content类型的外部资源,漏打就会白屏或图标丢失
  • WPF程序依赖.NET Framework或.NET RunTime,目标框架一定要写清楚,安装包里的前置组件要匹配
  • WPF的高DPI支持在客户机器上有时会出现字体模糊或布局错位,调试时多换几台分辨率不同的电脑测
  • 如果用到Prism或者MVVM框架,程序集数量比WinForm多不少,建议用recursesubdirs方式整体打包,不要只挑“需要的”文件

还有一个细节:WPF程序有时会引用一些原生DLL,比如用OpenCV做图像处理,这些原生DLL不会自动复制到输出目录。打包前要检查是否有独立存在的原生DLL,把它手动放进文件清单。

6.3 界面权限:管理员权限和UAC

海康客户端的很多操作涉及系统级资源,比如修改本地网络配置、加载驱动、写入系统注册表。这类程序装完最好让程序自身具备管理员权限。

策略有两种:

  • 程序manifest里声明管理员权限,每次运行都弹UAC
  • 安装时给程序目录设置权限,程序以普通用户运行,只有特定操作提权

内部工具类项目,我一般选择第一种,省事。面向客户的软件,选择第二种,体验更好。WPF和WinForm在manifest设置上没有本质区别,关键要记得设置并验证。

7. 打包前后必须跑通的验证清单

脚本写完了,安装包生成了,不代表交付完成。我每个月发版本前都要过一遍验证清单,这里分享给大家。

7.1 干净虚拟机上跑一遍安装

在开发环境上跑成功不是真成功,一定要在以下环境类型的干净机器上测试:

  • Windows 10 64位,无任何运行库
  • Windows 11 64位,有旧版本.NET环境
  • 带有标准杀毒软件的企业办公环境

虚拟机建议安装Windows评估版或合规授权版本,安装完之后不做任何额外配置,直接跑安装包,看能否顺利完成。

7.2 验证安装包内文件完整性和版本号

Inno Setup打完包,可以生成一个带校验码的文件清单,在安装结束后用脚本检测主程序版本号和关键DLL是否存在。这一步能有效防止“装完后打不开但不知道少了什么”的尴尬情况。

7.3 卸载后残留文件检查

卸载后检查下面这些位置:

  • 程序目录是否全部删除
  • 公共数据目录是否还剩了配置文件
  • 开始菜单和桌面快捷方式是否清除干净
  • 注册表里是否有残留的App项

这一轮检查过,这个安装包才算达到发布标准。

8. 常见问题与排查实录

这里列几个我在实际打包过程中遇到的典型问题,基本是客户现场反馈回来,然后我一步步定位出来的。

8.1 客户机器上双击主程序没反应

最常见的情况:程序安装完成,快捷方式也有,双击鼠标后什么反应也没有,任务管理器里也没有进程。

排查顺序:

  1. 先看事件查看器,.NET Runtime错误里有没有异常信息
  2. 缺依赖库是第一怀疑对象,用Dependency Walker或者直接看事件日志里报错的是哪个模块
  3. 如果日志里看到“Cannot load ... native library”,基本就是VC运行库没装或者版本不匹配
  4. 如果是x86/x64不匹配,会看到“BadImageFormatException”

处理的办法:检查安装脚本里运行库安装是否执行成功,同时检查程序编译目标架构和SDK架构是否匹配。

8.2 SDK初始化返回错误码,但开发机一切正常

开发机正常,客户机器报错,这个就很典型了。海康SDK的初始化失败码如果指向“加载动态库失败”,基本可以锁定:

  • SDK DLL没有随安装包拷贝到程序目录
  • 被安全软件拦截导致加载失败
  • SDK所需VC运行库缺失

我的处理技巧:在程序里把SDK的日志功能提前打开,日志会直接告诉你少了哪个DLL或者哪个依赖组件没就绪。别靠猜,看日志定位是最快的。

8.3 数据库连接不上的问题

客户端需要连本地数据库时,安装完成后经常遇到连接失败。排查重点:

  • 系统服务是否启动,比如SQLServer的服务是否正常运行
  • 配置文件中的连接串是否指向了当前机器的正确实例名
  • 数据库文件是否被安装包正确放置到指定路径

我通常在安装脚本中用[Run]段注册Windows服务,并用[Registry]段写入数据库路径,这样整个系统才真正“装好了”。

8.4 杀毒软件误报

Inno Setup生成的安装包有个特点:如果不做代码签名,很多杀毒软件会直接拦截。海康SDK包含一些底层驱动文件,更容易触发误报。

解决办法是给安装包加数字签名。内部项目如果预算有限,可以用自签名证书;对外发布的项目,还是建议买正规的代码签名证书。签名后的安装包在SmartScreen提示和杀毒软件拦截率上会有明显改善。

9. 关于脚本维护和持续集成的一句话建议

最后说一个容易被忽略的点:安装包脚本和代码一样需要版本管理。我推荐把Inno Setup脚本文件(.iss)、运行库路径说明、部署清单全部放进代码仓库里,和主程序同一次提交。这样每次发版,CI构建出程序集,紧接着用命令行编译安装包:

ISCC.exe HikClient_Setup.iss

ISCC是Inno Setup自带的命令行编译器,把它和Inno Setup安装目录关联后,打包全过程不需要人工操作。我最近一次发版本,整个流程从代码提交到生成安装包,总共不到十分钟。

如果你现在的项目还在靠人工在安装工具里面点鼠标选文件,强烈建议切换成脚本方式,哪怕只是把这个过程自动化,节省的时间都很可观。

海康客户端这类项目,打包说到底是“依赖版本管理”的延伸。只要把依赖清单、安装脚本、运行库和SDK的状态都管理到位,发版也不过是一条命令的事。我自己在打包上踩过的坑,全部集中在“没提前检查”、“架构不一致”、“权限没考虑”这三件事上。把这几个点提前堵住,后面基本就顺畅了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询