inno setup安装前判断进程是否存在及停止相应进程, 安装时自动卸载删除旧版本文件

目录

inno setup 安装时判断并关闭已经运行的应用程序exe

Inno Setup打包exe卸载旧版本

功能描述

注意

获取历史安装路径的代码如下:

卸载应用程序,删除整个安装目录

综上完整的脚本代码如下所示:


inno setup 安装时判断并关闭已经运行的应用程序exe

就很简单的一个功能,Inno setup制作的安装包,在安装时候,判断是否之前有本程序的实力在运行,运行的话需要终止他,貌似很简单,折腾了我1小时。
  网上找的好多方案,不理想不理想!我就给大家列举下这些我认为不理想的原因!
          

        网上方案1: 在Code段用FindWindowByWindowName、FindWindowByClassName……对不起我的客户端的标题是会变的啊!我的客户端主窗口是对话框啊,窗口类名都一样(#32770)啊!
  

        网上方案2: 用个叫IsTask.dll的外部扩展,Inno setup没,自己网上下,说白了就是个用c++写的一个dll,自己也能写,回头用Code pascal语言调用……,RunTask、KillTask用的这两个函数……,蛋疼的事情发生了,本来秒开的安装包,要卡个5秒以上在打开……怀疑是IsTask.dll破吧,自己写个,c++中char对应pascal中PAnsiChar,函数导出调用方案方法注意stdcall,弄好,还是通过进程名加载dll……结果……卡……5秒以上……原来是inno setup自己low……升级inno setup到最新5.5.9,一样有问题。


        网上方案3: 找啊找老半天,发现SETUP段里可以添加一个APPMUTEX,不错,我的exe里为了不能多开也弄了个非匿名的mutex,马上加上,点开安装……我了个去,结果只是提示你有你的exe在运行,自己去关闭吧……啥体验啊……


        我自己的方案,很简单通过checkmutex判断是否在运行,是的话通过ShellExec 打开cmd用taskkill杀死进程……完美解决,也不会加载dll卡的5秒,体验棒棒哒。

//安装时判断并关闭已经运行的应用exe

// 定义一个整数类型的变量 ErrorCode,用于存储执行 ShellExec 命令后的错误代码
var ErrorCode: Integer;
// 定义 InitializeSetup 函数,该函数返回一个布尔值
function InitializeSetup(): Boolean;
begin
if CheckForMutexes('MyAppMutex') then
       begin
            if MsgBox('检测到你的DocWatch.exe正在运行中!'#13'点击 "是" 关闭Doc.Watch.exe继续安装;'#13'点击 "否" 退出安装程序!', mbConfirmation, MB_YESNO) = IDYES then
               begin
               ShellExec('open', ExpandConstant('{cmd}'), '/c taskkill /f /t /im DocWatch.exe', '', SW_HIDE, ewNoWait, ErrorCode);
               Result:= true;
               end
            else
               Result:= false;
       end
   else
Result:=true;
end;

Inno Setup打包exe卸载旧版本

// 获取旧版本的卸载字符串
function GetUninstallString(): String;
var
  sUnInstPath: String;
  sUnInstallString: String;
begin
  // 构建注册表路径
  sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{{#MyUid}}_is1');

  // 初始化卸载字符串为空
  sUnInstallString := '';

  // 从 HKLM 注册表项中获取 UninstallString 值
  if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
    // 如果在 HKLM 中未找到,尝试从 HKCU 中获取
    RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);

  // 返回获取到的卸载字符串
  Result := sUnInstallString;
end;

// 判断是否需要升级(是否存在旧版本)
function IsUpgrade(): Boolean;
begin
  // 如果获取到的卸载字符串不为空,则存在旧版本
  Result := (GetUninstallString() <> '');
end;


// 卸载旧版本的软件
function UnInstallOldVersion(): Integer;
var
  sUnInstallString: String;
  iResultCode: Integer;
begin
  // 默认返回值为 0
  Result := 0;

  // 获取旧版本的卸载字符串
  sUnInstallString := GetUninstallString();

  // 如果卸载字符串不为空
  if sUnInstallString <> '' then
  begin
    // 去除卸载字符串中的引号
    sUnInstallString := RemoveQuotes(sUnInstallString);

    // 执行卸载命令,并等待执行完毕
    if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES', '', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
      Result := 3  // 卸载成功
    else
      Result := 2; // 卸载失败
  end
  else
    Result := 1; // 卸载字符串为空
end;

// 当安装步骤变化时触发的事件处理函数
procedure CurStepChanged(CurStep: TSetupStep);
begin
  // 当进入安装步骤时
  if CurStep = ssInstall then
  begin
    // 检查是否需要升级(是否存在旧版本)
    if IsUpgrade() then
    begin
      // 尝试卸载旧版本
      UnInstallOldVersion();
    end;
  end;
end;

功能描述
  • 比较版本号,如果版本号高于已安装的旧版本则卸载旧版本;
注意
  • 只有AppId相同才会对比,AppId不同继续安装;

 获取历史安装路径的代码如下:

//获取历史安装路径,Inno Setup保存的一些信息可自己在注册表中查看
//64位会映射到:计算机\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall

function GetInstallString(): String;
var
  InstallPath: String;
begin
  InstallPath := '{#MyAppInstallPath}';
  if RegValueExists(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{{#MyUid}}_is1', 'Inno Setup: App Path') then
    begin
      RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{{#MyUid}}_is1', 'Inno Setup: App Path', InstallPath)
    end;
  result := InstallPath;
end;

业务场景:有次客户反馈说,卸载应用程序没有卸载干净,安装目录下残留很多文件,特别是一些配置文件和数据库文件,涉及到一些数据安全机密。卸载程序应该把安装目录都要清除。操作如下:

卸载应用程序,删除整个安装目录

//卸载应用程序没有卸载干净,安装目录下残留很多文件,特别是一些配置文件和数据库文件,涉及到一些数据安全机密。卸载程序应该把安装目录都要清除。以下代码将卸载应用程序,并删除整个安装目录

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
  InstallDir: String;
begin
  // 获取安装目录
  InstallDir := ExpandConstant('{app}');

  case CurUninstallStep of
    usUninstall:
      begin
        // 如果安装目录存在,则删除整个目录及其内容
        if DirExists(InstallDir) then
          DelTree(InstallDir, True, True, True);

        // 删除安装根目录
        RemoveDir(ExtractFileDir(InstallDir));
      end;
  end;
end;

综上完整的脚本代码如下所示:

; 脚本由 Inno Setup 脚本向导 生成!
; 有关创建 Inno Setup 脚本文件的详细资料请查阅帮助文档!

#define MyAppName "DocWatch"
//程序图标路径,相对于iss脚本的相对路径
#define MyAppIcon "Install\bin\Gmep.ico"
#define MyAppVersion "3.2"
#define MyAppPublisher "CEEC"
#define MyAppExeName "CADSetup.exe"
#define docWatch "DocWatch.exe" 

#define InstallWindowsService "InstallWindowsService.exe" 

//待打包的文件路径,相对于iss脚本的相对路径
#define MyAppExePath "Install"
//程序默认安装目录
#define MyAppInstallPath "D:\GEDI\DocWatch"
//程序uuid,点工具生成唯一的GUID
#define MyUid "{A626D5BF-BB90-471F-BA24-06F77DB4F9C4}"      

[Setup]
; 注: AppId的值为单独标识该应用程序。
; 不要为其他安装程序使用相同的AppId值。
; (若要生成新的 GUID,可在菜单中点击 "工具|生成 GUID"。)
AppId={{#MyUid}}
//程序安装后的名字
AppName={#MyAppName} 
//程序版本号
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
//默认安装目录
DefaultDirName={#MyAppInstallPath}
//使用已安装版本的目录安装,为yes则默认选择已有的目录且不能选择
UsePreviousAppDir=no
//不显示选择开始菜单文件夹 向导页面
DisableProgramGroupPage=yes
; 以下行取消注释,以在非管理安装模式下运行(仅为当前用户安装)。
;PrivilegesRequired=lowest
//以管理权限运行安装
PrivilegesRequired=admin
//安装包生成后所在文件夹和文件名
OutputDir=C:\Users\user\Desktop\DocWatch
OutputBaseFilename={#MyAppName} V{#MyAppVersion}
SetupIconFile=F:\bigDataResultUp\DocWatch\Install\bin\Gmep.ico
//选择压缩方法,lzma为7z
Compression=lzma
//启用固态压缩,详见文档
SolidCompression=yes
//互斥体
APPMUTEX=MyAppMutex
//安装和卸载程序现代外观
WizardStyle=modern

[Languages]
Name: "chinesesimp"; MessagesFile: "compiler:Default.isl"

[Files]
Source: "{#MyAppExePath}\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#MyAppExePath}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; 注意: 不要在任何共享系统文件上使用“Flags: ignoreversion”
 ; 安装前判断进程,dll文件放在inno的安装目录中


[Icons]
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"

[Run]
// [Run]- 用来指定在程序完成安装后,在安装程序显示最终对话框前要执行的一些程序
Filename: "{app}\bin\{#docWatch}"; Description: "{cm:LaunchProgram,{#StringChange(docWatch, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppExeName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent

[UninstallRun]
Filename: "{cmd}"; Parameters: "/C ""taskkill /im DocWatch.exe /f /t"


[Code]

//安装时判断并关闭已经运行的应用exe

// 定义一个整数类型的变量 ErrorCode,用于存储执行 ShellExec 命令后的错误代码
var ErrorCode: Integer;
// 定义 InitializeSetup 函数,该函数返回一个布尔值
function InitializeSetup(): Boolean;
begin
if CheckForMutexes('MyAppMutex') then
       begin
            if MsgBox('检测到你的DocWatch.exe正在运行中!'#13'点击 "是" 关闭Doc.Watch.exe继续安装;'#13'点击 "否" 退出安装程序!', mbConfirmation, MB_YESNO) = IDYES then
               begin
               ShellExec('open', ExpandConstant('{cmd}'), '/c taskkill /f /t /im DocWatch.exe', '', SW_HIDE, ewNoWait, ErrorCode);
               Result:= true;
               end
            else
               Result:= false;
       end
   else
Result:=true;
end;

//卸载应用程序没有卸载干净,安装目录下残留很多文件,特别是一些配置文件和数据库文件,涉及到一些数据安全机密。卸载程序应该把安装目录都要清除。以下代码将卸载应用程序,并删除整个安装目录
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
  InstallDir: String;
begin
  // 获取安装目录
  InstallDir := ExpandConstant('{app}');

  case CurUninstallStep of
    usUninstall:
      begin
        // 如果安装目录存在,则删除整个目录及其内容
        if DirExists(InstallDir) then
          DelTree(InstallDir, True, True, True);

        // 删除安装根目录
        RemoveDir(ExtractFileDir(InstallDir));
      end;
  end;
end;



// 获取旧版本的卸载字符串
function GetUninstallString(): String;
var
  sUnInstPath: String;
  sUnInstallString: String;
begin
  // 构建注册表路径
  sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{{#MyUid}}_is1');

  // 初始化卸载字符串为空
  sUnInstallString := '';

  // 从 HKLM 注册表项中获取 UninstallString 值
  if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
    // 如果在 HKLM 中未找到,尝试从 HKCU 中获取
    RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);

  // 返回获取到的卸载字符串
  Result := sUnInstallString;
end;

// 判断是否需要升级(是否存在旧版本)
function IsUpgrade(): Boolean;
begin
  // 如果获取到的卸载字符串不为空,则存在旧版本
  Result := (GetUninstallString() <> '');
end;


// 卸载旧版本的软件
function UnInstallOldVersion(): Integer;
var
  sUnInstallString: String;
  iResultCode: Integer;
begin
  // 默认返回值为 0
  Result := 0;

  // 获取旧版本的卸载字符串
  sUnInstallString := GetUninstallString();

  // 如果卸载字符串不为空
  if sUnInstallString <> '' then
  begin
    // 去除卸载字符串中的引号
    sUnInstallString := RemoveQuotes(sUnInstallString);

    // 执行卸载命令,并等待执行完毕
    if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES', '', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
      Result := 3  // 卸载成功
    else
      Result := 2; // 卸载失败
  end
  else
    Result := 1; // 卸载字符串为空
end;

// 当安装步骤变化时触发的事件处理函数
procedure CurStepChanged(CurStep: TSetupStep);
begin
  // 当进入安装步骤时
  if CurStep = ssInstall then
  begin
    // 检查是否需要升级(是否存在旧版本)
    if IsUpgrade() then
    begin
      // 尝试卸载旧版本
      UnInstallOldVersion();
    end;
  end;
end;





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值