简介:面向ArcGIS Engine桌面应用开发者与部署维护人员,这份资源聚焦应用程序打包部署难题,系统讲解如何将ArcGIS Engine Runtime和.NET Framework 3.5 SP1正确打包进安装程序,避免分发时因环境依赖缺失导致的运行失败。资源为单个docx格式技术文档,压缩包仅2.24MB,内容源于ESRI中国内部培训资料,条理清晰、截图丰富,可直接作为操作参考。目前已有650人学习下载。文档覆盖两条打包路径:一条是基于Visual Studio 2008自带安装项目,从新建Setup项目、添加主输出、创建快捷方式到排除Esri DLL的完整流程;另一条是使用InstallShield将Runtime和.NET Framework与应用程序合并打包的详细操作,包括项目助手向导、安装目录配置和快捷方式设计。同时针对打包过程中常见的两个问题给出了排查思路,能帮助开发者避开Esri DLL重复打包、目标机器环境检测等陷阱,大幅提升AE程序交付的完整性与成功率。
1. 打包 arcGIS Engine 应用程序,先搞清楚“你在打包什么”
很多用 arcGIS Engine 做过二次开发的人,第一次做部署包时都会有一个错觉:把 bin 目录里的 exe 和 dll 拷到另一台机器上,装个 .NET Framework,双击就能跑。结果通常是双击后闪退,或者直接弹“无法加载 DLL“arcgis版本相关组件””。这不是代码问题,而是 arcGIS Engine 应用程序打包这件事从一开始就被理解窄了。你要打包的不是“你的程序”,而是“你的程序 + 它依赖的 ArcObjects 运行时 + 许可授权 + 环境配置”四层内容的组合。多数人只打了第一层,所以到目标机器上必然缺东西。
这篇文章解决的就是这条完整链路:开发机上哪些文件要带走、哪些文件不能带走、目标机器上的 arcGIS Engine Runtime 怎么装、许可怎么免交互地初始化、装完之后程序还是起不来时怎么定位。适合做桌面 GIS 工具或行业业务系统交付的开发者,也适合做实施部署的人参考。下面直接进入依赖盘点,这才是打包能不能成功的地基。
2. 打包前先盘点依赖:bin 目录里哪些 dll 必须随包走
2.1 开发时引用的 arcgis 相关 dll,是拷走还是引用运行时
用 arcGIS Engine 开发的程序,在 Visual Studio 里一定会引用一组 Esri 开头的程序集,比如 ESRI.ArcGIS.System、ESRI.ArcGIS.Geometry、ESRI.ArcGIS.Carto、ESRI.ArcGIS.Controls 等。在开发机上,这些 dll 来自安装 arcGIS Engine Developer Kit 时的安装目录,默认在C:\Program Files (x86)\ArcGIS\DeveloperKit10.x\DotNet这类路径下。编译之后,Visual Studio 会把这些引用复制到你的 bin 输出目录,所以你的 exe 旁边会出现一堆 Esri.*.dll。
这带来第一个打包决策点:程序集到底是“随包携带”还是“依赖目标机器上的运行时”?
如果随包携带,包体会变大,但每台机器是自包含的,只要目标机器上有对应的 arcGIS Engine Runtime 和许可,程序集版本不会和机器上其他 GIS 软件冲突。如果依赖目标机器的运行时,理论上只要目标机器装了 Runtime,程序集可以从 GAC 或安装目录加载,但这样做风险很高:目标机器可能存在多个 arcGIS 版本,.NET 程序集绑定策略一旦解析到错误版本,程序会直接抛异常。
我一般会选“随包携带程序集”,也就是让 Visual Studio 把引用复制到本地。这样打包时只需要确定一件事:这台目标机器上有足够版本的 Runtime,且许可初始化成功。如果你用的是 10.2 开发,却在只有 10.8 Runtime 的机器上部署,程序照样起不来,因为 ArcObjects 的底层原生组件版本对不上。
2.2 开发机 bin 目录里哪些文件看起来像 arcGIS Engine 文件,但绝对不能拷
打开开发机的 bin 目录,除了你自己的 exe、config 和一堆 Esri.*.dll,还有三类文件要特别区分。
第一类是ESRI.ArcGIS开头的若干个*.dll,这是托管程序集,可以拷走,但要注意它们有“版本化”的特性。你开发时用的版本号(比如 10.2)和运行时不一定一致。如果你在部署时把 10.2 的托管 dll 拷给了装有 10.8 Runtime 的机器,加载时 .NET 可能因为强名称版本不匹配直接拒绝加载。这时需要在 app.config 里做 bindingRedirect,或者统一开发环境和 Runtime 版本。这个后面第五节再细说。
第二类是项目引用里带ESRI.ArcGIS前缀但实际来自ArcGIS\Desktop或ArcGIS\Engine安装目录的组件,例如ESRI.ArcGIS.3DAnalyst.dll、ESRI.ArcGIS.Geodatabase.dll,这些是托管包装,但它们底层调用的是非托管的ArcObjects原生库。这些原生库不在你的 bin 目录里,而是装在 Runtime 安装目录中。所以那些 dll 拷走没有意义,你又不可能把整个原生目录搬过去。
第三类是许可相关文件,比如软件授权文件或初始化许可的缓存文件,它们一般不在 bin 目录中。如果发现开发机上有一个license相关的目录或文件,那些是开发许可,千万别顺手打进部署包。曾经有一个项目把开发机的ArcGIS\Engine许可配置目录整个塞进安装包,导致目标机器上程序读取到一套已经过期的开发许可,最后所有功能初始化失败,排查了很久才发现问题。
2.3 拿一张自查表,把依赖项列全
打包前找一个干净的虚拟机,按下面的列表逐项核对,能少踩很多坑:
| 依赖项 | 随包带走还是目标机安装 | 说明 |
|---|---|---|
| ESRI.ArcGIS.*.dll(托管程序集) | 随包带走 | 让发布目录自包含,避免 GAC 版本冲突 |
| ArcObjects 原生运行时库 | 目标机安装 | 只能通过 arcGIS Engine Runtime 安装程序提供 |
| .NET Framework | 目标机安装或随包检测 | 安装包需检测版本,缺失时引导安装 |
| arcGIS Engine Runtime | 目标机安装 | 必须和开发版本主版本一致,10.x 系列内部还建议同小版本 |
| 许可(License) | 目标机配置 | 单机许可文件或浮动许可服务器配置,必须初始化 |
| 数据和配置文件 | 随包带走 | 如 mxd、gdb、json 配置,注意路径写相对路径 |
| 其他第三方 dll(如 GDAL、Newtonsoft.Json) | 随包带走 | 只要是工程引用的,全部带上 |
注意“目标机安装”这一列,不是让用户手动点下一步,而是安装包启动时用静默安装参数自动装。下一节就给出一个可以抄的脚本。
3. 用 Inno Setup 做一个可复现的 arcGIS Engine 部署包
3.1 为什么用 Inno Setup,而不是 InstallShield 或手工拷贝
给 arcGIS Engine 程序做安装包,安装工具的选择直接影响后期维护成本。InstallShield 是商业软件,功能全但脚本语法复杂,出问题不好排;WiX 学习曲线陡,写一个带自定义操作的安装包要维护大量 XML;手工拷贝脚本最灵活,但没法给用户提供卸载入口和桌面快捷方式,也不适合交付给非技术客户。
Inno Setup 是免费软件,脚本用 Pascal 风格语法,支持静默安装、自定义安装目录、写注册表、安装后执行其他程序。更重要的是它支持在安装过程中调用另一个 exe 或 msi 并等待其完成,这正好用来驱动 arcGIS Engine Runtime 的安装。所以下面用 Inno Setup 做示例,因为它是这个场景下最容易多人维护的方案。
3.2 最小可用的 iss 脚本模板
下面这个脚本做了三件事:把你的 bin 目录装到目标机的指定位置;再静默安装 arcGIS Engine Runtime(以 10.x 的安装介质为例);最后留下一个 Start 菜单快捷方式。
; arcgis_engine_app_setup.iss ; Inno Setup 脚本,包含 arcGIS Engine Runtime 静默安装调用 #define MyAppName "GIS 工具箱" #define MyAppVersion "1.0.0" #define MyAppExeName "GISTool.exe" #define EngineRuntimeSetup "Setup.exe" ; arcGIS Engine Runtime 安装介质 #define EngineRuntimeSilentArgs "/qb" ; 静默安装参数,见下方说明 [Setup] AppId={{8A3C2B1E-2D4A-4B6C-9A1D-3F5E6C7A8B9C} AppName={#MyAppName} AppVersion={#MyAppVersion} DefaultDirName={autopf}\{#MyAppName} OutputBaseFilename=GIS_Tool_Setup Compression=lzma2 SolidCompression=yes ; 程序集随包安装,关闭“目标机 GAC 优先”的奇奇怪怪加载逻辑 UsePreviousAppDir=no [Files] ; 你的整个 bin 目录 Source: "..\bin\*"; DestDir: "{app}"; Flags: recursesubdirs createallsubdirs ; arcGIS Engine Runtime 安装介质放进安装包,不额外要求用户单独下载 Source: "install\AERuntime\{#EngineRuntimeSetup}"; DestDir: "{tmp}\AERuntime"; Flags: deleteafterinstall [Run] ; 先装 Runtime,然后启动你的程序主安装逻辑 Filename: "{tmp}\AERuntime\{#EngineRuntimeSetup}"; Parameters: {#EngineRuntimeSilentArgs}; \ StatusMsg: "正在安装 arcGIS Engine Runtime,请稍候..."; Flags: waituntilterminated; \ Check: EngineRuntimeNotInstalled Filename: "{app}\{#MyAppExeName}"; Description: "启动 GIS 工具箱"; \ Flags: postinstall nowait skipifsilent [Icons] Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" [Code] function EngineRuntimeNotInstalled(): Boolean; begin // 简单检测:判断注册表里是否存在 Engine Runtime 的安装标记 // 10.x 的安装标记通常位于 HKLM\SOFTWARE\ESRI\ArcGIS\Engine 或 // HKLM\SOFTWARE\WOW6432Node\ESRI\ArcGIS\Engine,这里只做目标键存在性检测 Result := not RegKeyExists(HKLM, 'SOFTWARE\ESRI\ArcGIS\Engine10.x'); end;这段脚本里的Source用recursesubdirs把整个 bin 递归装进去,比一条条列 dll 路径好维护得多。{tmp}目录用来暂存 Runtime 安装介质,装完自动删除,避免用户 C 盘残留安装文件。
3.3 参数怎么调:静默参数和等待逻辑
EngineRuntimeSilentArgs这里写的是/qb,这是常见 Windows Installer 的界面对话参数:/qb表示仅显示进度条,不显示交互确定页;/qn表示完全无界面。arcGIS Runtime 的 Setup.exe 实际上是一个引导程序,它支持把参数透传给内层 msi,常见的静默组合是/qb,但要注意有的版本在接受/qn时会在最后停留在一个“安装完成”界面等待用户点确定,这在无人值守安装时会有问题。
Flags: waituntilterminated是必须的。如果不加这个标记,Inno Setup 不会等 Runtime 装完就直接往下走,你的程序先装好了,但 ArcObjects 原生库还不存在,用户双击时依然是“加载 dll 失败”。这个“顺序依赖”是安装包最容易忽略的点:程序文件落盘和运行时安装是异步的,必须用这个标志把两步串行起来。
3.4 为什么建议把 Runtime 安装介质塞进安装包
有人会觉得 arcGIS Engine Runtime 安装包体积大,动不动几百 MB,把它塞进自己的安装包会让交付文件变得很臃肿。但从部署成功率角度看,这样最稳:第一,目标机器上有没有 Runtime、是什么版本,实施人员现场根本不可控,你挨个去问客户机器上装没装过 arcGIS,沟通成本极高;第二,从官方渠道单独下载需要登录并选对版本,客户现场的 IT 运维不一定有这个耐心。
把 Runtime 安装介质内置后,安装包变成“双阶段安装”,第一阶段装 Runtime,第二阶段装你的程序。这比让客户先装 Runtime 再装你的程序要可靠得多。体积大一点可以接受,因为面向内部的行业应用交付频率不高,体积不是首要矛盾。
4. 许可初始化是 arcGIS Engine 部署里最容易失败的环节
4.1 单机许可和浮动许可:打包时要决定走哪条路
arcGIS Engine 应用在目标机器上能不能跑起来,最终取决于许可是否初始化成功。打包前必须确定客户现场采用哪种授权方式。常见的两种:单机许可(Single Use)和浮动许可(Concurrent Use)。
单机许可适合在封闭网络环境、无许可服务器的机器上使用。部署时把许可文件放到目标机器指定位置,然后通过命令行工具初始化。浮动许可适合几十台机器共用一套授权,部署时只需写入许可服务器地址,客户端启动时去服务器取席位。
在安装包里做许可处理时,建议做一个选择页面或配置文件项,让实施人员按现场情况填写。写死在脚本里会让维护变成灾难,比如客户原来有 50 台浮动许可,后来买了几台独立机器要用单机许可,你就得重新出包。
4.2 许可初始化命令与常见做法
在开发机上装完 arcGIS Engine 后,系统会带一个许可管理工具(名字通常是“ArcGIS Administrator”)。界面上可以操作的事,部署时都要尽可能变成命令行。因为安装包是无界面安装,不可能让现场人员打开 GUI 去点。
常见做法是安装完成后调用许可初始化命令。以一个 10.x 版本的示例,写入浮动许可服务器地址的方式是在注册表里直接写入服务器名:
# PowerShell 脚本:设置 arcGIS Engine 浮动许可服务器地址 # 以管理员权限运行。32 位程序在 64 位系统上要同时检查两个注册表位置 $regPath = "HKLM:\SOFTWARE\ESRI\License10.x\ArcGIS Engine" $regPathWow64 = "HKLM:\SOFTWARE\WOW6432Node\ESRI\License10.x\ArcGIS Engine" # LICENSE_SERVER 的取值示例:27004@licserver.contoso.com $licenseServer = "27004@licserver.contoso.com" if (Test-Path $regPath) { New-ItemProperty -Path $regPath -Name "LICENSE_SERVER" -Value $licenseServer -PropertyType String -Force } if (Test-Path $regPathWow64) { New-ItemProperty -Path $regPathWow64 -Name "LICENSE_SERVER" -Value $licenseServer -PropertyType String -Force } # 检测写入结果 Get-ItemProperty -Path $regPath | Select-Object LICENSE_SERVER这段命令只在已有上述注册表路径的机器上写入,如果没有对应键,说明 Runtime 没装成功,需要回头排查安装阶段。27004是浮动许可服务默认端口,如果客户的许可服务器改过端口,这里的值也要跟着变。
4.3 初始化许可的 3 个必调参数
许可相关配置有三个参数值得在部署时仔细核对:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| LICENSE_SERVER | 27004@主机名或主机名 | 浮动许可地址。只写主机名的话用默认端口,但显式写端口更不容易踩需要额外解析的坑 |
| 许可级别(初始化等级) | 和你开发时一致 | 例如开发时是 Engine 标准版,目标机器也要有同样等级的许可。等级不够时初始化不报错,但某些类在创建时抛出“无法创建对象”异常 |
| 许可缓存文件路径 | 记入安装日志 | 单机许可的缓存文件路径变化会导致程序找不到许可,安装时记录在案,排错时少走弯路 |
这里最容易踩的坑是:许可初始化没报错,但实际没生效。开发机上双击运行程序,界面正常弹出;拿到目标机器上,程序也能弹窗,但一执行打开地图、读 shp 这类操作就崩。这种“部分功能失效”的现象通常就是许可等级不对,或者程序里初始化许可的代码写死了所有功能模块,而目标机器的许可只有部分模块。
5. 目标机器上装完跑不起来?按这四个位置定位问题
很多人装完 arcGIS Engine 程序后遇到闪退,第一反应是重装 Runtime,或者换一台机器试,这其实没有命中要害。我用过的最有效的定位办法是按下面四个位置逐个检查。
先看事件查看器:Windows 日志里“应用程序”一栏,找到对应程序的错误记录。如果错误是“CLR20r3”,说明是 .NET 程序集版本加载失败;如果错误指向某个 esri 原生 dll,说明 Runtime 没装或者版本不匹配;如果错误是“0xc000007b”,大概率是 32/64 位不匹配。这三类原因对应三种完全不同的修法,所以先看事件日志比胡乱重装效率高得多。
再看程序目录下的 config 文件。arcGIS Engine 程序通常会有 app.config 或 exe.config,里面有 bindingRedirect 节点。开发机上跑得好好的机器,目标机上报“未能加载文件或程序集 ESRI.ArcGIS.Version”,多半是这里的版本重定向缺失或范围太小。不要直接删 bindingRedirect,也不要一口气配十几个 dll 的重定向,先找到报错的那个版本号,把它加进去。
第三看许可状态。在目标机器上打开许可管理工具的界面,看许可是否显示“可用”。如果显示“不可用”或“无许可”,回到第四节的注册表命令,检查 LICENSE_SERVER 是否被安装后的其他程序改写过。曾见过一种情况:机器上装了 arcGIS Desktop 又装了 Engine 程序,Desktop 的许可管理把自己设置成了默认,覆盖了 Engine 程序的服务器配置。
第四看出厂自带的数据路径。很多 arcGIS Engine 程序启动时要读取固定的工作空间或 mxd 路径,开发机上用绝对路径写死了,部署到目标机后路径不存在,程序在初始化阶段就直接退出。这不是打包问题,却是部署失败最常见的原因。在安装包里加一个“数据目录选择”步骤,或者程序里改成相对路径,都能避免。
最后补一个实用技巧:发布包含 arcGIS Engine Runtime 的安装包后,在目标机上先不运行你自己的程序,而是打开 Runtime 自带的一个简单验证工具(比如 ArcGIS 安装目录里的一些示例或许可验证程序),能不能正常打开,能打开就说明 Runtime 和许可没问题,问题在你的程序配置上;打不开则回头检查 Runtime 安装和许可初始化。这样把“运行时问题”和“程序问题”一刀切开,排错路径会清晰很多。
本文还有配套的精品资源,点击获取