Inno_setup制作升级包必须面临的几个问题
这两天的时间一直在制作应用程序的升级包,期间碰到一些问题这里一并记录下来,相信这是制作升级包必须面临和解决的问题:
1. 升级包安装程序如何不再产生新的安装、卸载程序
Inno_setup中AppId是用来标识某个应用程序的唯一标识,因此升级包中的AppId字段应该和原始安装程序的AppId相同。
CreateUninstallRegKey字段,改值设置为no则安装程序将不会在控制面板的“添加/删除程序”中再创建一个。当这个关键字设置为 no时,UpdateUninstallAppName通常也设置为 no。
UpdateUninstallAppName如果为 yes, 当添加到一个已存在的卸载记录时,安装程序将以当前的安装程序的 AppName 替换在卸载记录中的 AppName。卸载记录中的 AppName决定了卸载程序显示的标题。如果你的安装程序只是一个升级或附加到一个已存在的程序,并且你不想改变卸载程序的标题,那么你可以设置该值为 no。
2. 如何检测以前的应用程序正在运行
判断某个应用程序是否正在运行,这里可以采用两种方式:一种是应用程序的进程是否正在运行;一种是通过窗口名称来检测。采用第一种方式时要引入ISTask.dll文件(它通常可以在Inno_setup安装包里面找到),实例代码如下:
1) 通过进程检测是否正在运行
首先确保ISTask.dll文件和脚本文件位于同一目录:
其次确保[Files]段中添加:
最后[Code]段中加入一下函数调用:
2) 通过窗口检测是否正在运行,主要是通过FindWindowByWindowName()函数,下面以检测有道词典是否正在运行为例:
以上两种情况可以依据自己的实际情况来选择,如果你的应用程序窗口固定那么采用第二种检测方式会方便一些;但是如果你无法确定窗口名称或你的窗口名称是会变化的,则采用第一种方式会更好。
3. 如何修改控制面板里原有程序的版本信息
制作升级包不得不面对的问题是版本升级,那么像下面所示如何修改控制面板中存在的版本信息是我们不得不面对的问题:
如何修改呢?看看我们的注册表就知道了:
图中标识的就是控制面板中可以看到的所有信息,那么解决方案就是修改注册表中的信息,具体代码如下:
具体涉及的两个操作就是:RegQueryStringValue()查询注册表和RegWriteStringValue()修改注册表,具体使用一看便知。
4. 如何修改控制面板里原有程序的显示图标
有了上面的如何修改控制面板里的版本信息,相信你已经猜到了,修改控制面板里应用程序的显示图标也是通过修改注册表来实现的,这里要提到的是:DisplayIcon字段,用来定义控制面板中应用程序图标的显示路径,代码如下:
升级包程序运行之后,控制面板中的信息为:
可以看到应用程序的显示图标和版本信息都已经修改了,再看下注册表里面,添加了DisplayIcon字段,其它信息也已经修改:
5. 如何检测浏览器正在运行
适用于当前主流浏览器,代码如下:
6. 如何进行文件查找及拷贝
不管是在安装包制作或升级包制作过程中,通常面临着文件的拷贝,除了[Files]段中的文件拷贝,请看如下的查找及拷贝操作:
FileSearch('rdp.tmp' , ExpandConstant('{app}'))表示查找应用程序安装目录下是否存在rdp.tmp文件,如果存在则返回该文件的绝对路径,如果不存在则返回' '
FileCopy(ExpandConstant('{tmp}\rdp.tmp') , ExpandConstant('{app}\rdp.tmp') , false)是将临时目录下的rdp.tmp文件拷贝到应用程序安装目录下,这里要注意两点:
1> 第二个参数目标文件,一定要带着最终的文件名,如果只是一个目录的路径,则拷贝操作会出错。
2> 第三个参数为true代表如果最终文件存在则拷贝操作失败,如果为false则拷贝操作会覆盖原有文件。
总结:以上就是2天的收获,升级包制作完成。Inno_setup是个比较强大的工具,里面还可以运行cmd命令。
相关代码:
1 // 卸载时判断浏览器是否正在运行 2 function InitializeUninstall(): Boolean; 3 var 4 iehWnd, ffhWnd, chrhWnd, b360hWnd, safhWnd, i: Integer; 5 begin 6 result:=true; 7 iehWnd := FindWindowByClassName('IEFrame'); 8 ffhWnd := FindWindowByClassName('MozillaWindowClass'); 9 b360hWnd := FindWindowByClassName('360se6_Frame'); 10 chrhWnd := FindWindowByClassName('Chrome_WidgetWin_1'); 11 safhWnd := FindWindowByClassName('{1C03B488-D53B-4a81-97F8-754559640193}'); 12 i := 0; 13 14 while (iehWnd>0) or (ffhWnd>0) or (b360hWnd>0) or (chrhWnd>0) or (safhWnd>0) do 15 begin 16 if i > 0 then 17 begin 18 Msgbox('请确保所有浏览器都已关闭!', mbInformation, MB_OK); 19 end; 20 21 if Msgbox('插件更新程序检测到浏览器正在运行。' #13#13 '请您先关闭所有浏览器,单击“是”继续更新,否则按“否”退出安装', mbConfirmation, MB_YESNO) = idNO then 22 begin 23 Result:=false; 24 iehWnd :=0; 25 ffhWnd :=0; 26 b360hWnd :=0; 27 chrhWnd :=0; 28 safhWnd :=0; 29 end else begin 30 Result :=true; //卸载程序继续 31 iehWnd := FindWindowByClassName('IEFrame'); 32 ffhWnd := FindWindowByClassName('MozillaWindowClass'); 33 b360hWnd := FindWindowByClassName('360se6_Frame'); 34 chrhWnd := FindWindowByClassName('Chrome_WidgetWin_1'); 35 safhWnd := FindWindowByClassName('{1C03B488-D53B-4a81-97F8-754559640193}'); 36 end; 37 i := i+1; 38 end; 39 end; 40 41 42 // 检测应用服务是否正在使用 added by houqd 2013/12/17 43 // 该函数利用FindWindowByWindowName(),只能通过窗口的名字来判断 44 // 不适合现在的情况,采用另一种方式判断后台进程是否正在进行 45 function ifRunningDesktop():Boolean; 46 var 47 isRunning:Integer; 48 cycleCount:Integer; 49 begin 50 Result:=true; 51 cycleCount:=0; 52 isRunning:=FindWindowByWindowName('有道词典'); 53 while isRunning <> 0 do 54 begin 55 if cycleCount > 0 then 56 begin 57 Msgbox('请确保客户端已关闭!', mbInformation, MB_OK); 58 end; 59 if MsgBox('升级程序检测到客户端正在运行。' #13#13 '您必须先关闭客户端然后单击“是”继续安装,或按“否”退出安装!',mbConfirmation, MB_YESNO) = idNO then 60 begin 61 Result:=false; 62 isRunning:=0; 63 end else begin 64 Result:=true; 65 isRunning:=FindWindowByWindowName('VSODesktop'); 66 end; 67 cycleCount:=cycleCount +1 ; 68 end; 69 end; 70 71 // 判断某个进程是否正在运行,利用安装包里面自带的ISTask.dll插件 72 function RunTask(FileName: string; bFullpath: Boolean): Boolean; 73 external 'RunTask@files:ISTask.dll stdcall delayload'; 74 75 function ifBrowserIsRunning():Boolean; 76 var 77 iehWnd, ffhWnd, chrhWnd, b360hWnd, safhWnd, i: Integer; 78 begin 79 iehWnd := FindWindowByClassName('IEFrame'); 80 ffhWnd := FindWindowByClassName('MozillaWindowClass'); 81 b360hWnd := FindWindowByClassName('360se6_Frame'); 82 chrhWnd := FindWindowByClassName('Chrome_WidgetWin_1'); 83 safhWnd := FindWindowByClassName('{1C03B488-D53B-4a81-97F8-754559640193}'); 84 85 if (iehWnd>0) or (ffhWnd>0) or (b360hWnd>0) or (chrhWnd>0) or (safhWnd>0) then 86 begin 87 Result:=true; 88 end else begin 89 Result:=false; 90 end; 91 end; 92 93 94 // 检测vsodesktop进程是否正在运行,即正在打开这vso应用软件 95 // added by houqd 2013/12/18 96 function ifVsoIsRunning():Boolean; 97 var 98 pstate:Boolean; 99 begin 100 Result:= RunTask('VSODesktop.exe', false); 101 end; 102 103 104 // 升级包通过修改注册表,更改控制面板中已安装软件的版本信息 105 // added by houqd 2013/12/18 106 function updateVersion():Boolean; 107 var 108 ResultStr:String; 109 nDisplayName:String; 110 nVersion:String; 111 begin 112 113 Result:=true; 114 nDisplayName:='{#PreDisplayName}'+'{#MyAppVersion}'; 115 nVersion:='{#MyAppVersion}'; 116 117 // 修改版本信息 118 if RegQueryStringValue(HKLM,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1','DisplayName',ResultStr) then 119 begin 120 if nDisplayName <> ResultStr then 121 begin 122 RegWriteStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1', 'DisplayName', nDisplayName); 123 end; 124 end; 125 126 if RegQueryStringValue(HKLM,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1','DisplayVersion',ResultStr) then 127 begin 128 if nVersion <> ResultStr then 129 begin 130 RegWriteStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1', 'DisplayVersion', nVersion) 131 end; 132 end; 133 end; 134 135 // 升级包通过修改注册表,更改控制面板中已安装软件的显示图标 136 // added by houqd 2013/12/18 137 function updateDisplayIcon():Boolean; 138 var 139 ResultStr:String; 140 nDisplayIcon:String; 141 installLocation:String; 142 begin 143 Result:=true; 144 145 RegQueryStringValue(HKLM,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1','InstallLocation',installLocation); 146 nDisplayIcon:=installLocation+'VSODesktop.exe'; 147 148 // 如果DisplayIcon该键值存在则说明它原本就有图标,现在要对比更新 149 if RegQueryStringValue(HKLM,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1','DisplayIcon',ResultStr) then 150 begin 151 if nDisplayIcon <> ResultStr then 152 begin 153 RegWriteStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1', 'DisplayIcon', nDisplayIcon) 154 end; 155 end else begin 156 RegWriteStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1', 'DisplayIcon', nDisplayIcon) 157 end; 158 end; 159 160 rdpFileExsits:=FileSearch('rdp.tmp',ExpandConstant('{app}')); // 如果文件存在则返回绝对路径,如果不存在则返回空 161 if rdpFileExsits = '' then 162 begin 163 Exec(ExpandConstant('{cmd}'), '/c wmic qfe get hotfixid | find "KB2592687" > '+ExpandConstant('{tmp}\rdp.tmp'), '', SW_HIDE, ewWaitUntilTerminated, ResultCode); 164 FileCopy(ExpandConstant('{tmp}\rdp.tmp'),ExpandConstant('{app}\rdp.tmp'),false); 165 end;
加油,坚持每天的学习,少年!