Inno_setup制作升级包必须面临的几个问题

摘要:
卸载记录中的AppName决定了卸载程序显示的标题。Inno_setup是个比较强大的工具,里面还可以运行cmd命令。

这两天的时间一直在制作应用程序的升级包,期间碰到一些问题这里一并记录下来,相信这是制作升级包必须面临和解决的问题:

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文件和脚本文件位于同一目录:

Inno_setup制作升级包必须面临的几个问题第1张

其次确保[Files]段中添加:

Inno_setup制作升级包必须面临的几个问题第2张

最后[Code]段中加入一下函数调用:

Inno_setup制作升级包必须面临的几个问题第3张

2) 通过窗口检测是否正在运行,主要是通过FindWindowByWindowName()函数,下面以检测有道词典是否正在运行为例:

Inno_setup制作升级包必须面临的几个问题第4张

以上两种情况可以依据自己的实际情况来选择,如果你的应用程序窗口固定那么采用第二种检测方式会方便一些;但是如果你无法确定窗口名称或你的窗口名称是会变化的,则采用第一种方式会更好。

3. 如何修改控制面板里原有程序的版本信息

制作升级包不得不面对的问题是版本升级,那么像下面所示如何修改控制面板中存在的版本信息是我们不得不面对的问题:

Inno_setup制作升级包必须面临的几个问题第5张

如何修改呢?看看我们的注册表就知道了:

Inno_setup制作升级包必须面临的几个问题第6张

图中标识的就是控制面板中可以看到的所有信息,那么解决方案就是修改注册表中的信息,具体代码如下:

Inno_setup制作升级包必须面临的几个问题第7张

具体涉及的两个操作就是:RegQueryStringValue()查询注册表和RegWriteStringValue()修改注册表,具体使用一看便知。

4. 如何修改控制面板里原有程序的显示图标

有了上面的如何修改控制面板里的版本信息,相信你已经猜到了,修改控制面板里应用程序的显示图标也是通过修改注册表来实现的,这里要提到的是:DisplayIcon字段,用来定义控制面板中应用程序图标的显示路径,代码如下:

Inno_setup制作升级包必须面临的几个问题第8张

升级包程序运行之后,控制面板中的信息为:

Inno_setup制作升级包必须面临的几个问题第9张

可以看到应用程序的显示图标和版本信息都已经修改了,再看下注册表里面,添加了DisplayIcon字段,其它信息也已经修改:

Inno_setup制作升级包必须面临的几个问题第10张

5. 如何检测浏览器正在运行

适用于当前主流浏览器,代码如下:

Inno_setup制作升级包必须面临的几个问题第11张

6. 如何进行文件查找及拷贝

不管是在安装包制作或升级包制作过程中,通常面临着文件的拷贝,除了[Files]段中的文件拷贝,请看如下的查找及拷贝操作:

Inno_setup制作升级包必须面临的几个问题第12张

FileSearch('rdp.tmp' , ExpandConstant('{app}'))表示查找应用程序安装目录下是否存在rdp.tmp文件,如果存在则返回该文件的绝对路径,如果不存在则返回' '

FileCopy(ExpandConstant('{tmp} dp.tmp') , ExpandConstant('{app} dp.tmp') , false)是将临时目录下的rdp.tmp文件拷贝到应用程序安装目录下,这里要注意两点:

1> 第二个参数目标文件,一定要带着最终的文件名,如果只是一个目录的路径,则拷贝操作会出错。

2> 第三个参数为true代表如果最终文件存在则拷贝操作失败,如果为false则拷贝操作会覆盖原有文件。

总结:以上就是2天的收获,升级包制作完成。Inno_setup是个比较强大的工具,里面还可以运行cmd命令。

相关代码:

// 卸载时判断浏览器是否正在运行
function InitializeUninstall(): Boolean;
var
    iehWnd, ffhWnd, chrhWnd, b360hWnd, safhWnd, i: Integer;
begin
    result:=true;
    iehWnd := FindWindowByClassName('IEFrame');
    ffhWnd := FindWindowByClassName('MozillaWindowClass');
    b360hWnd := FindWindowByClassName('360se6_Frame');
    chrhWnd := FindWindowByClassName('Chrome_WidgetWin_1');
    safhWnd := FindWindowByClassName('{1C03B488-D53B-4a81-97F8-754559640193}');
    i := 0;
    while (iehWnd>0) or (ffhWnd>0) or (b360hWnd>0) or (chrhWnd>0) or (safhWnd>0) do
    begin
      if i > 0 then
      begin
         Msgbox('请确保所有浏览器都已关闭!', mbInformation, MB_OK);
      end;
      if Msgbox('插件更新程序检测到浏览器正在运行。'  #13#13 '请您先关闭所有浏览器,单击“是”继续更新,否则按“否”退出安装', mbConfirmation, MB_YESNO) = idNO then
      begin
           Result:=false;
           iehWnd :=0;
           ffhWnd :=0;
           b360hWnd :=0;
           chrhWnd :=0;
           safhWnd :=0;
      end else begin
        Result :=true;  //卸载程序继续
        iehWnd := FindWindowByClassName('IEFrame');
        ffhWnd := FindWindowByClassName('MozillaWindowClass');
        b360hWnd := FindWindowByClassName('360se6_Frame');
        chrhWnd := FindWindowByClassName('Chrome_WidgetWin_1');
        safhWnd := FindWindowByClassName('{1C03B488-D53B-4a81-97F8-754559640193}');
      end;
      i := i+1;
    end;
end;
// 检测应用服务是否正在使用  added by houqd 2013/12/17
// 该函数利用FindWindowByWindowName(),只能通过窗口的名字来判断
// 不适合现在的情况,采用另一种方式判断后台进程是否正在进行
function ifRunningDesktop():Boolean;
var
   isRunning:Integer;
   cycleCount:Integer;
begin
    Result:=true;
    cycleCount:=0;
    isRunning:=FindWindowByWindowName('有道词典');
    while isRunning <> 0 do
    begin
        if cycleCount > 0 then
        begin
           Msgbox('请确保客户端已关闭!', mbInformation, MB_OK);
        end;
        if MsgBox('升级程序检测到客户端正在运行。' #13#13 '您必须先关闭客户端然后单击“是”继续安装,或按“否”退出安装!',mbConfirmation, MB_YESNO) = idNO then
        begin
           Result:=false;
           isRunning:=0;
        end else begin
           Result:=true;
           isRunning:=FindWindowByWindowName('VSODesktop');
        end;
        cycleCount:=cycleCount +1 ;
    end;
end;
// 判断某个进程是否正在运行,利用安装包里面自带的ISTask.dll插件
function RunTask(FileName: string; bFullpath: Boolean): Boolean;
external 'RunTask@files:ISTask.dll stdcall delayload';
function ifBrowserIsRunning():Boolean;
var
   iehWnd, ffhWnd, chrhWnd, b360hWnd, safhWnd, i: Integer;
begin
    iehWnd := FindWindowByClassName('IEFrame');
    ffhWnd := FindWindowByClassName('MozillaWindowClass');
    b360hWnd := FindWindowByClassName('360se6_Frame');
    chrhWnd := FindWindowByClassName('Chrome_WidgetWin_1');
    safhWnd := FindWindowByClassName('{1C03B488-D53B-4a81-97F8-754559640193}');
    if (iehWnd>0) or (ffhWnd>0) or (b360hWnd>0) or (chrhWnd>0) or (safhWnd>0) then
    begin
       Result:=true;
    end else begin
       Result:=false;
    end;
end;
// 检测vsodesktop进程是否正在运行,即正在打开这vso应用软件
// added by houqd 2013/12/18
function ifVsoIsRunning():Boolean;
var
    pstate:Boolean;
begin
    Result:= RunTask('VSODesktop.exe', false);
end;
// 升级包通过修改注册表,更改控制面板中已安装软件的版本信息
// added by houqd 2013/12/18
function updateVersion():Boolean;
var
   ResultStr:String;
   nDisplayName:String;
   nVersion:String;
begin
   Result:=true;
   nDisplayName:='{#PreDisplayName}'+'{#MyAppVersion}';
   nVersion:='{#MyAppVersion}';
   // 修改版本信息
   if RegQueryStringValue(HKLM,'SOFTWAREMicrosoftWindowsCurrentVersionUninstall{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1','DisplayName',ResultStr) then
   begin
      if nDisplayName <> ResultStr then
      begin
          RegWriteStringValue(HKLM, 'SOFTWAREMicrosoftWindowsCurrentVersionUninstall{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1', 'DisplayName', nDisplayName);
      end;
   end;
   if RegQueryStringValue(HKLM,'SOFTWAREMicrosoftWindowsCurrentVersionUninstall{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1','DisplayVersion',ResultStr) then
   begin
      if nVersion <> ResultStr then
      begin
          RegWriteStringValue(HKLM, 'SOFTWAREMicrosoftWindowsCurrentVersionUninstall{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1', 'DisplayVersion', nVersion)
      end;
   end;
end;
// 升级包通过修改注册表,更改控制面板中已安装软件的显示图标
// added by houqd 2013/12/18
function updateDisplayIcon():Boolean;
var
  ResultStr:String;
  nDisplayIcon:String;
  installLocation:String;
begin
  Result:=true;
  RegQueryStringValue(HKLM,'SOFTWAREMicrosoftWindowsCurrentVersionUninstall{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1','InstallLocation',installLocation);
  nDisplayIcon:=installLocation+'VSODesktop.exe';
  // 如果DisplayIcon该键值存在则说明它原本就有图标,现在要对比更新
  if RegQueryStringValue(HKLM,'SOFTWAREMicrosoftWindowsCurrentVersionUninstall{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1','DisplayIcon',ResultStr) then
  begin
     if nDisplayIcon <> ResultStr then
     begin
        RegWriteStringValue(HKLM, 'SOFTWAREMicrosoftWindowsCurrentVersionUninstall{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1', 'DisplayIcon', nDisplayIcon)
     end;
  end else begin
        RegWriteStringValue(HKLM, 'SOFTWAREMicrosoftWindowsCurrentVersionUninstall{C77BFCB0-66A4-4D04-82D9-FF74356FA0B1}_is1', 'DisplayIcon', nDisplayIcon)
  end;
end;
rdpFileExsits:=FileSearch('rdp.tmp',ExpandConstant('{app}')); // 如果文件存在则返回绝对路径,如果不存在则返回空
 if rdpFileExsits = '' then
 begin
 Exec(ExpandConstant('{cmd}'), '/c wmic qfe get hotfixid | find "KB2592687" > '+ExpandConstant('{tmp}
dp.tmp'), '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
 FileCopy(ExpandConstant('{tmp}
dp.tmp'),ExpandConstant('{app}
dp.tmp'),false);
 end;

加油,坚持每天的学习,少年!

免责声明:文章转载自《Inno_setup制作升级包必须面临的几个问题》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇多线程详解,一篇文章彻底搞懂多线程中各个难点svg.js教程及使用手册详解(一)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Windows下手动配置Oracle Client的要点

Windows下手动配置Oracle Client的要点我的Windows上原有Oracle 9的客户端, 想使用cx_Oracle和python些点东西, cx_Oracle官网上没有for python2.7和Oracle9的安装包, 但有for oracle10的安装包. 所以需要先安装Oracle 10 client. 可能是因为卸载Oracle...

Qt界面美化 QSS

目前发现在Qt-Design中右击控件,可以选择Change StyleSheet ------------------------以下总结不太对 刚接触Qt,发现Qt Design无法对每个控件进行颜色风格设置。正在纳闷如此受欢迎的开发工具,怎么会没有这种,Delphi,VB,VC,C#都具备的基本功能呢? 后来在CSDN上才知道,Qt已经走在这些工...

C#进阶系列——WebApi 跨域问题解决方案:CORS

  阅读目录 一、跨域问题的由来 二、跨域问题解决原理 三、跨域问题解决细节 1、场景描述 2、场景测试 四、总结 正文 前言:上篇总结了下WebApi的接口测试工具的使用,这篇接着来看看WebAPI的另一个常见问题:跨域问题。本篇主要从实例的角度分享下CORS解决跨域问题一些细节。 WebApi系列文章 C#进阶系列——WebApi接口...

互动直播中的前端技术——即时通讯

前言 在疫情期间,上班族开启了远程办公,体验了各种远程办公软件。老师做起了主播,学生们感受到了被钉钉支配的恐惧,歌手们开启了在线演唱会,许多综艺节目也变成了在线直播。在这全民互动直播的时期,我们来聊聊互动直播中的即时通讯技术在前端中的使用。 即时通讯技术 即时通讯(Instant Messaging,简称IM)是一个实时通信系统,允许两人或多人使用网络实时...

easy-wechat

https://www.easywechat.com/docs/master/installation -----其它的回复 创建菜单自定义菜单事件 地理位置回复素材发送一次性订阅消息 与 发送模板消息 -------- easy-wechat获取微信服务器 IP (或IP段) $ips = $app->base->getValidIps();...

Google天涯问答提问遭遇

一星期前,我在一个店中听到一首歌,但不知道歌名,于是就用手机录下来,准备拿到网上询问网友。 于是昨天我将录音文件上传到UUShare,然后将问题发布到谷歌天涯问答,原文如下: 这首歌叫什么?(付录音) 我在一个商店里听到的,就用手机录下了,好像是一首韩国歌,北京麦当劳以前也曾播放过,就是一直不知道叫什么,求救~ 录音文件地址:http://www.uu...