制作部署安装包:Inno Setup

前一篇尝试Office 2003 VSTO的开发、部署有提到用VS开发一个简单的VSTO程序。打包C/S程序,我首先想到的是VS里自带的Setup Project。很遗憾,VS2012及后面的版本都剔除了Setup Project,改用InstallShield Limited Edition。

Setup Project配置起来N麻烦,如:配置完成了之后,一旦修改了项目的东西然后重新生成,只有移除原来定义好的快捷方式、主输出,然后重新设置才能应用修 改。而ISLE,对于一些简单的打包,基本上都是满足了的,而且整个操作过程都有界面,动动鼠标就行了;里面有部分功能是可以写代码定制的,不过要授权收 费!这是我个人的使用心得,安装打包用得不多,有误之处,还请多多指教。

无意中发现了Inno这个小东西(官网地址),然后深深地被它吸引了。麻雀虽小,五脏俱全,可以完全免费使用,最主要的是它允许自己使用Pascal语言编写定制脚本。

网上挺多资料的,但很多都是雷同,且测试时部分有bug。下面贴上自己的一个代码栗子,参考了网上的几篇文章,然后修改整理的。

需要注意的:

1、打包指定文件(夹)时,该文件(夹)必须存在文件,不然编译时提示错误。路径(可使用相对路径)CheckOfficeConsole\DotNetFramework必须要存在文件,可以是任何类型的。

  1. Source: "CheckOfficeConsole\DotNetFramework\*"; DestDir: "{tmp}"; Flags: ignoreversion

2、检测.net framework,如果不存在则从指定网址下载安装包时,需要用到isxdl.dll。这个dll需要下载并安装ISTool

3、.net framework 的下载地址,我找到了除v3.0、v1版本以外的安装包地址,测试时都可用。未来微软网站也许会对这些资源包地址更新,所以不保证一直可用。

4、安装过程中,可通过Inno的函数读取指定目录的.ini文件,并获得文件里的参数值。这个太赞了有木有!一来可以减少在Inno脚本里硬编码,二来可以在安装过程中初始化相关数据。如:Output目录有一个setup.ini文件,里面的内容为:

  1. [Custom]
  2. dotNetVersion = v4.

Inno的读取代码:

  1. function GetCustomConfig(key:string):string;
  2. var
  3. myValue:string;
  4. begin
  5. myValue:=ExpandConstant('{ini:{src}\Setup.ini,Custom,'+key+'}')
  6. result := myValue;
  7. end;
  8.  
  9. //使用
  10. //.....
  11. GetCustomConfig('dotNetVersion');
  12. //.....

完整版:

  1. ; Script generated by the Inno Setup Script Wizard.
  2. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
  3. ; Ivan 2015-1-30
  4.  
  5. #define MyAppName "VSTO Excel by Ivan"
  6. #define MyAppVersion "1.0"
  7. #define MyAppPublisher "My Company, Inc."
  8. #define MyAppURL "http://www.IvanBy.com/"
  9. #define MyAppExeName "CheckOfficeConsole.exe"
  10.  
  11. [Setup]
  12. ; NOTE: The value of AppId uniquely identifies this application.
  13. ; Do not use the same AppId value in installers for other applications.
  14. ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
  15. AppId={{6DFC5AE2-4844-4440-A6B3-284E15A14AEA}
  16. AppName={#MyAppName}
  17. AppVersion={#MyAppVersion}
  18. ;AppVerName={#MyAppName} {#MyAppVersion}
  19. AppPublisher={#MyAppPublisher}
  20. AppPublisherURL={#MyAppURL}
  21. AppSupportURL={#MyAppURL}
  22. AppUpdatesURL={#MyAppURL}
  23. DefaultDirName={pf}\{#MyAppName}
  24. DefaultGroupName={#MyAppName}
  25. OutputBaseFilename=setup
  26. Compression=lzma
  27. SolidCompression=yes
  28.  
  29. [Languages]
  30. Name: "english"; MessagesFile: "compiler:Default.isl"
  31.  
  32. [Tasks]
  33. Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
  34.  
  35. [Files]
  36. Source: C:\Program Files (x86)\ISTool\isxdl.dll; Flags: dontcopy;
  37. Source: "CheckOfficeConsole\bin\Release\CheckOfficeConsole.exe"; DestDir: "{app}"; Flags: ignoreversion
  38. Source: "CheckOfficeConsole\DotNetFramework\*"; DestDir: "{tmp}"; Flags: ignoreversion
  39. Source: "Excel2010Setup\Excel2010Setup\Express\DVD-5\DiskImages\*"; DestDir: "{app}\2010"; Flags: ignoreversion recursesubdirs createallsubdirs
  40. ; NOTE: Don't use "Flags: ignoreversion" on any shared system files
  41.  
  42. [Icons]
  43. Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
  44. Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
  45. Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
  46.  
  47. ;更改显示在程序中显示的消息文本
  48. [Messages]
  49. BeveledLabel=Ivan Code
  50.  
  51. [Run]
  52. ;Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
  53. Filename: "{app}\{#MyAppExeName}"
  54.  
  55. [Code]
  56. var
  57. dotNetDownloadNeeded: boolean;
  58. dotNetLocalPath:string;
  59.  
  60. procedure isxdl_AddFile(URL, Filename: PAnsiChar);
  61. external 'isxdl_AddFile@files:isxdl.dll stdcall';
  62. function isxdl_DownloadFiles(hWnd: Integer): Integer;
  63. external 'isxdl_DownloadFiles@files:isxdl.dll stdcall';
  64. function isxdl_SetOption(Option, Value: PAnsiChar): Integer;
  65. external 'isxdl_SetOption@files:isxdl.dll stdcall';
  66.  
  67. //检测是否存在特定版本的.net framework
  68. function IsDotNetDetected(version: string; service:cardinal): boolean;
  69. // Indicates whether the specified version and service pack of the .NET Framework is installed.
  70. //
  71. // version -- Specify one of these strings for the required .NET Framework version:
  72. // 'v1.1.4322' .NET Framework 1.1
  73. // 'v2.0.50727' .NET Framework 2.0
  74. // 'v3.0' .NET Framework 3.0
  75. // 'v3.5' .NET Framework 3.5
  76. // 'v4\Client' .NET Framework 4.0 Client Profile
  77. // 'v4\Full' .NET Framework 4.0 Full Installation
  78. // 'v4.5' .NET Framework 4.5
  79. //
  80. // service -- Specify any non-negative integer for the required service pack level:
  81. // 0 No service packs required
  82. // 1, 2, etc. Service pack 1, 2, etc. required
  83. var
  84. key: string;
  85. install, release, serviceCount: cardinal;
  86. check45, success: boolean;
  87. begin
  88. // .NET 4.5 installs as update to .NET 4.0 Full
  89. if version = 'v4.5' then begin
  90. version := 'v4\Full';
  91. check45 := true;
  92. end else
  93. check45 := false;
  94.  
  95. // installation key group for all .NET versions
  96. key := 'SOFTWARE\Microsoft\NET Framework Setup\NDP\' + version;
  97.  
  98. // .NET 3.0 uses value InstallSuccess in subkey Setup
  99. if Pos('v3.0', version) = 1 then begin
  100. success := RegQueryDWordValue(HKLM, key + '\Setup', 'InstallSuccess', install);
  101. end else begin
  102. success := RegQueryDWordValue(HKLM, key, 'Install', install);
  103. end;
  104.  
  105. // .NET 4.0/4.5 uses value Servicing instead of SP
  106. if Pos('v4', version) = 1 then begin
  107. success := success and RegQueryDWordValue(HKLM, key, 'Servicing', serviceCount);
  108. end else begin
  109. success := success and RegQueryDWordValue(HKLM, key, 'SP', serviceCount);
  110. end;
  111.  
  112. // .NET 4.5 uses additional value Release
  113. if check45 then begin
  114. success := success and RegQueryDWordValue(HKLM, key, 'Release', release);
  115. success := success and (release >= 378389);
  116. end;
  117.  
  118. result := success and (install = 1) and (serviceCount >= service);
  119. end;
  120.  
  121. //准备安装.net framework需要的条件(本地还是联网)
  122. function PreInstallDotNet(dotNetName:string;dotNetDownloadUrl:string):boolean;
  123. begin
  124. if (not IsAdminLoggedOn()) then begin
  125. MsgBox('您电脑安装 Microsoft .NET Framework 需要管理员权限', mbInformation, MB_OK);
  126. Result := false;
  127. end else begin
  128. dotNetLocalPath := ExpandConstant('{src}') + '\'+dotNetName;
  129. if not FileExists(dotNetLocalPath) then begin
  130. dotNetLocalPath := ExpandConstant('{tmp}') + '\'+dotNetName;
  131. if not FileExists(dotNetLocalPath) then begin
  132. isxdl_AddFile(dotNetDownloadUrl, dotNetLocalPath);
  133. dotNetDownloadNeeded := true;
  134. end;
  135. end;
  136.  
  137. SetIniString('install', 'dotnetRedist', dotNetLocalPath, ExpandConstant('{tmp}\dep.ini'));
  138. end;
  139.  
  140. end;
  141.  
  142. //执行安装.net framework
  143. function DoInstallDotNet():boolean;
  144. var
  145. hWnd: Integer;
  146. ResultCode: Integer;
  147. begin
  148. result := true;
  149. hWnd := StrToInt(ExpandConstant('{wizardhwnd}'));
  150.  
  151. // don’t try to init isxdl if it’s not needed because it will error on < ie 3
  152. if dotNetDownloadNeeded then begin
  153. isxdl_SetOption('label', '正在下载 Microsoft .NET Framework');
  154. isxdl_SetOption('des-c-r-i-p-tion', '您还未安装Microsoft .NET Framework. 请您耐心等待几分钟,下载完成后会安装到您的的计算机中。');
  155. if isxdl_DownloadFiles(hWnd) = 0 then result := false;
  156. end;
  157.  
  158. if result = true then begin
  159. if Exec(ExpandConstant(dotNetLocalPath), '/qb', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then begin
  160. // handle success if necessary; ResultCode contains the exit code
  161. if not (ResultCode = 0) then begin
  162. result := false;
  163. end;
  164. end else begin
  165. // handle failure if necessary; ResultCode contains the error code
  166. result := false;
  167. end;
  168. end;
  169.  
  170. end;
  171.  
  172. //检测是否安装了等于大于指定版本的.net framework
  173. function IsIncludeFramework(version: string): boolean;
  174. var
  175. isInclued:boolean;
  176. begin
  177.  
  178. //最高版本的
  179. if IsDotNetDetected('v4.5',0) then begin
  180. isInclued := true;
  181. end else if version = 'v4.5' then begin
  182. PreInstallDotNet('dotNetFx45_Full_setup.exe','http://download.microsoft.com/download/B/A/4/BA4A7E71-2906-4B2D-A0E1-80CF16844F5F/dotNetFx45_Full_setup.exe');
  183. end else if IsDotNetDetected('v4\Full',0) then begin
  184. isInclued := true;
  185. end else if version = 'v4\Full' then begin
  186. PreInstallDotNet('dotNetFx40_Full_x86_x64.exe','http://download.microsoft.com/download/9/5/A/95A9616B-7A37-4AF6-BC36-D6EA96C8DAAE/dotNetFx40_Full_x86_x64.exe');
  187. end else if IsDotNetDetected('v4\Client',0) then begin
  188. isInclued := true;
  189. end else if version = 'v4\Client' then begin
  190. PreInstallDotNet('dotNetFx40_Client_x86_x64.exe','http://download.microsoft.com/download/5/6/2/562A10F9-C9F4-4313-A044-9C94E0A8FAC8/dotNetFx40_Client_x86_x64.exe');
  191. end else if IsDotNetDetected('v3.5',0) then begin
  192. isInclued := true;
  193. end else if Pos('v3.5',version) = 1 then begin
  194. PreInstallDotNet('dotNetFx35setup.exe','http://download.microsoft.com/download/7/0/3/703455ee-a747-4cc8-bd3e-98a615c3aedb/dotNetFx35setup.exe');
  195. end else if IsDotNetDetected('v3.0',0) then begin
  196. isInclued := true;
  197. end else if Pos('v3.0',version) = 1 then begin
  198. PreInstallDotNet('dotNetFx35setup.exe','http://download.microsoft.com/download/7/0/3/703455ee-a747-4cc8-bd3e-98a615c3aedb/dotNetFx35setup.exe');
  199. end else if IsDotNetDetected('v2.0.50727',0) then begin
  200. isInclued := true;
  201. end else if Pos('v2',version) = 1 then begin
  202. PreInstallDotNet('dotnetfx.exe','http://download.microsoft.com/download/5/6/7/567758a3-759e-473e-bf8f-52154438565a/dotnetfx.exe');
  203. end else if IsDotNetDetected('v1.1.4322',0) then begin
  204. isInclued:= true;
  205. end else if Pos('v1',version)=1 then begin
  206. PreInstallDotNet('dotNetFx35setup.exe','http://download.microsoft.com/download/7/0/3/703455ee-a747-4cc8-bd3e-98a615c3aedb/dotNetFx35setup.exe');
  207. end;
  208.  
  209. result := isInclued;
  210. end;
  211.  
  212. //取得自定义的配置
  213. // Setup.ini
  214. // [Custom]
  215. // dotNetVersion = v4.5
  216. function GetCustomConfig(key:string):string;
  217. var
  218. myValue:string;
  219. begin
  220. myValue:=ExpandConstant('{ini:{src}\Setup.ini,Custom,'+key+'}')
  221. result := myValue;
  222. end;
  223.  
  224. function InitializeSetup(): Boolean;
  225. begin
  226. //do something
  227.  
  228. result:= true;
  229. end;
  230.  
  231. function NextButtonClick(CurPage: Integer): Boolean;
  232. var
  233. dotNetVersion:string;
  234. begin
  235. Result := true;
  236.  
  237. if (CurPage = wpReady) then begin
  238.  
  239. dotNetVersion := GetCustomConfig('dotNetVersion');
  240. if Length(dotNetVersion) = 0 then begin
  241. dotNetVersion := 'v4.0';
  242. end else if not (Pos('v',dotNetVersion) = 1) then begin
  243. dotNetVersion := 'v'+dotNetVersion;
  244. end;
  245.  
  246. if not IsIncludeFramework(dotNetVersion) then begin
  247. if not DoInstallDotNet() then begin
  248. MsgBox('当前操作需要安装.NET Framework ' + dotNetVersion + '或以上版本。'#13#13
  249. '在尝试自动安装期间,似乎出现一些小问题(或用户取消了安装),'#13
  250. '请重试尝试安装。', mbInformation, MB_OK);
  251. result:= false;
  252. end;
  253. end;
  254.  
  255. end;
  256.  
  257. end;
  258.  
  259. procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
  260. var
  261. ErrorCode: Integer;
  262. begin
  263. case CurUninstallStep of
  264. usUninstall:
  265. begin
  266. // 正在卸载
  267. end;
  268. usPostUninstall:
  269. begin
  270. //卸载完成
  271. ShellExec('open', 'http://www.IvanBy.com', '', '', SW_SHOW, ewNoWait, ErrorCode)
  272.  
  273. end;
  274. end;
  275. end;

制作部署安装包:Inno Setup的更多相关文章

  1. Advanced Installer 制作.NetWeb部署安装包

    原文:Advanced Installer 制作.NetWeb部署安装包 因为是.Net的Web应用程序,所以想用Advanced Installer 调用Dll实现安装部署. 因为我需要自己定制参数 ...

  2. C#进阶系列——使用Advanced Installer制作IIS安装包(二:配置安装包依赖项和自定义dll)

    前言:上篇C#进阶系列——使用Advanced Installer制作IIS安装包(一:配置IIS和Web.config)介绍了下使用Advanced Installer配置IIS和Web.confi ...

  3. DevExpress控件库 开发使用经验总结3 制作项目安装包

    2015-01-27 使用DevExpress控件包开发C/S项目完成后,部署前需要制作本地安装包.本文还是使用“SetupFactory”安装工厂来制作安装包.在以前的系列文章中详细介绍过该工具的使 ...

  4. 使用Advanced Installer制作IIS安装包(二:配置安装包依赖项和自定义dll)

    前言:上篇使用Advanced Installer制作IIS安装包(一:配置IIS和Web.config)介绍了下使用Advanced Installer配置IIS和Web.config的过程,操作起 ...

  5. 使用WinRar软件制作程序安装包

    之前我写过使用好压软件打包程序,见随笔: 使用好压(HaoZip)软件打包EverEdit制作安装程序 - Fetty - 博客园http://www.cnblogs.com/fetty/p/4907 ...

  6. 7z制作自解压安装包

    像7z和winRAR这样的压缩工具都支持制作自解压的文件.所谓自解压的文件就是不需要目标机器上安装解压工具,通过运行压缩包自己即可解压出压缩包中的文件.下面我们就介绍一下如何利用7z的自解压功能制作应 ...

  7. installshield制作的安装包卸载时提示重启动的原因以及解决办法

    原文:installshield制作的安装包卸载时提示重启动的原因以及解决办法 有时候卸载installshield制作的安装包程序,卸载完会提示是否重启电脑以完成所有卸载,产生这个提示的常见原因有如 ...

  8. 使用Inno Setup 制作软件安装包详细教程(与开发语言无关)

    前言:关于如何制作一个软件安装包的教程,与编程语言无关.以下,请看详情~ 1.下载Inno Setup,下载地址:https://jrsoftware.org/isinfo.php 2.下载最新版本即 ...

  9. python制作安装包(setup.py)

    1.制作setup.py from distutils.core import setup setup(name='Myblog', version='1.0', description='My Bl ...

随机推荐

  1. maven搭建java ee项目

    1.点击File->New->Other,选择maven project   2.选择maven project,点击Next,,而后再点击next,进入如下界面 如图选择最后一个,点击n ...

  2. DOI EXCEL显示报表

    我这个是比较不规则的数据填充 1.程序开头,定义一个工作区,存对应单元格的值: BEGIN OF TY_EXCEL, C031() TYPE C, C032() TYPE C, C033() TYPE ...

  3. 5月5日 while、do{}while

    while .do{}while 一.while的死循环 while (1 == 1)//只要表达式里是true,就是死循环 { //循环内容 } 二.do{}while 不管while是否满足,首先 ...

  4. Div CSS absolute与relative的区别小结

    absolute:绝对定位,CSS 写法“ position: absolute; ”,它的定位分两种情况,如下: 1. 没有设定 Top.Right.Bottom.Left 的情况,默认依据父级的“ ...

  5. 7款适用老旧设备并对初学者非常友好的轻量级Linux发行版

    我们由从 7 到 1 的顺序向大家介绍. 7. Linux Lite 正如其名,Linux Lite 是 Linux 发行版的一个轻量级版本,用户并不需要强大的硬件就可以将它跑起来,而且其使用非常简单 ...

  6. 从客户端中检测到有潜在危险的Request.Form值的解决方法

    描述:从客户端中检测到有潜在危险的Request.Form值的解决方法asp.net 2.0 通常解决办法将.aspx文件中的page项添加ValidateRequest="false&qu ...

  7. 一个QMLListView的例子--

    一般人不知道怎么去过滤ListView里面的数据,下面是一个转载的文章:http://imaginativethinking.ca/use-qt-quicks-delegatemodelgroup/ ...

  8. Swift - 自动布局库SnapKit的使用详解4(样例1:实现一个登录页面)

    前面的几篇文章讲解了自动布局库SnapKit的使用方法.本文通过一个完整的样例(登录页面)来演示在实际项目中如何使用SnapKit来实现自动化布局的.1,效果图如下

  9. 小记:利用递归调用循环寻找MP3文件的方法。

    private void findMp3Data(File mp3file) { File[] filelist = mp3file.listFiles(); if (filelist != null ...

  10. treap 1296 营业额统计

    有一个点答案错误,求大神指教 #include<cstdio>#include<iostream>#include<cstdlib>#include<ctim ...