提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
最近有一个需求是springboot项目实现从IE浏览器跳转至谷歌浏览器并打包成windows环境下可执行exe文件,以达到客户的小白操作。
提示:以下是本篇文章正文内容,下面案例可供参考,欢迎各位技术大牛指正。
一、开发工具
1.IDEA开发工具2.exe4j Wizard
3.Inno Setup 编译器
二、Springboot实现IE浏览器跳转至谷歌浏览源码
1.获取谷歌浏览器可执行文件路径
这里我用过三种方式:
第一种是从windows注册机中获取谷歌浏览器的地址。
第二种是直接在C盘写死预先设置的路径,然后用innoSteup把谷歌浏览器运行环境与springboot项目一起打包,并将打包后的文件夹指向代码写死的路径,以方便代码可以读取到谷歌浏览器的可执行文件。(相当于把谷歌浏览器的运行环境也一起打包了,具体做法下面会具体介绍)。个人推荐使用第二种,因为不同型号的电脑,同一电脑不同用户其注册机会不断地变化,根本无法确定谷歌浏览器的可执行文件的路径。而且这么做不需要客户安装浏览器,也可以打开谷歌浏览器。这里需要注意的是需要根据客户电脑操作系统选择相应的谷歌浏览器版本,我这里集成了32位和64位操作系统版本的谷歌浏览器。
第三种是从外部配置文件中读取
由于第二种方式谷歌浏览器路径是由自己写死的,大家可以选择路径,所以这里贴上第一种和第三种的代码。
第一种:从windows注册机中获取谷歌浏览器的地址,这里我已经封装好了一个工具类(工具类中的ReadPropertiesUtils工具类是是第三种方式所用的工具类,代码在下面。),仅供参考:
代码如下(示例):
package com.luckyun.routing.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.Properties;
/**
* <p>Title:utils</p>
*
* @description: 依据操作系统环境读取本地浏览器安装路径
* @author: ywj
* @create: 2020-08-29 15:09
*/
public class Registery {
private static final Logger logger = (Logger) LoggerFactory.getLogger(Registery.class);
//windows10系统谷歌浏览器注册机默认地址
private static final String GOOLE_HKEY_LOCAL_MACHINE_WIN10 = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\ChromeHTML\\Application";
//windows7系统谷歌浏览器注册机默认地址
private static final String GOOLE_HKEY_LOCAL_MACHINE_WIN7 = "HKEY_CURRENT_USER\\Software\\AppDataLow\\Software\\JavaSoft\\DeploymentProperties";
//WindowsXP系统谷歌浏览器注册机默认地址
private static final String GOOLE_HKEY_LOCAL_MACHINE_WINXP = "HKEY_CLASSES_ROOT\\ChromeHTML\\shell\\open\\command";
/**
*
*@Description: 获取本机的windows环境下谷歌浏览器可执行文件路径-路径读取优先级(C盘application.properties中address地址优先于从本机注册机中的地址)
*@Author: ywj
*@Param: []
*@Return: java.lang.String
*@Date: 2020/8/30 15:51
**/
public static String getBrowserExePath() throws IOException {
Process process = null;
String path = "";
String line;
try {
Map<String, String> readProperties = ReadPropertiesUtils.getProperties();
if (readProperties != null && !StringUtils.isEmpty(readProperties.get("address"))){
path = readProperties.get("address");
}else {
//获取当前的系统属性集
Properties pop = System.getProperties();
String systemOsName = pop.getProperty("os.name");
if (!StringUtils.isEmpty(systemOsName) && systemOsName.equals("Windows 7")){
process = Runtime.getRuntime().exec("reg query ".concat(GOOLE_HKEY_LOCAL_MACHINE_WIN7));
}else if (!StringUtils.isEmpty(systemOsName) && systemOsName.equals("Windows 10")){
process = Runtime.getRuntime().exec("reg query ".concat(GOOLE_HKEY_LOCAL_MACHINE_WIN10));
}else if (!StringUtils.isEmpty(systemOsName) && systemOsName.equals("Windows XP")){
process = Runtime.getRuntime().exec("reg query ".concat(GOOLE_HKEY_LOCAL_MACHINE_WINXP));
}
if (process != null){
InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream());
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
while ((line = bufferedReader.readLine()) != null) {
if (line.contains("chrome.exe")){
path = line.toString();
path = path.substring(path.indexOf(":")-1,path.lastIndexOf(".exe")+4);
break;
}
}
if (inputStreamReader != null){
inputStreamReader.close();
}
}
}
}catch (Exception e){
logger.error("注册机获取谷歌浏览器路径异常!",e.getMessage());
}finally {
if (process !=null){
if (process.getInputStream() != null){
process.getInputStream().close();
}
process.getOutputStream().close();
}
}
return path;
}
}
第三种是从外部配置文件中读取,这里我已经封装好了一个工具类,仅供参考:
代码如下(示例):
package com.luckyun.routing.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* <p>Title:ReadPropertiesUtils</p>
*
* @description: 读取配置文件
* @author: ywj
* @create: 2020-08-30 17:24
*/
public class ReadPropertiesUtils {
private static final Logger logger = (Logger) LoggerFactory.getLogger(ReadPropertiesUtils.class);
//文件路径
private static final String filePath = "C://luckyun//application.properties";
/**
*
*@Description: 获取properties文件中的内容,并返回map
*@Author: ywj
*@Param: []
*@Return: java.util.Map<java.lang.String,java.lang.String>
*@Date: 2020/8/31 9:18
**/
public static Map<String, String> getProperties() throws IOException {
Map<String, String> map = new HashMap<String, String>();
InputStream inputStream = null;
Properties properties = new Properties();;
try {
File file = new File(filePath);
if (!file.exists()){
return null;
}else {
inputStream = new BufferedInputStream(new FileInputStream(file));
properties.load(inputStream);
Set<Map.Entry<Object, Object>> entrySet = properties.entrySet();
for (Map.Entry<Object, Object> entry : entrySet) {
map.put((String) entry.getKey(), (String) entry.getValue());
}
}
} catch (Exception e) {
logger.error("外部配置文件解析异常!",e.getMessage());
}finally {
if (inputStream != null){
inputStream.close();
}
}
return map;
}
}
2.该SpringBoot项目所需要的POM和相应的配置文件
POM代码
代码如下(示例):
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.luckyun</groupId>
<artifactId>routing</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>routing</name>
<description>routingHop project for Spring Boot</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
<!-- 排除自带的logback依赖 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--引入thymeleaf的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!--打包成windows服务-->
<plugin>
<groupId>cn.joylau.code</groupId>
<artifactId>joylau-springboot-daemon-windows</artifactId>
<version>1.0.RELEASE</version>
<executions>
<execution>
<id>make-win-service</id>
<phase>package</phase>
<goals>
<goal>make-win-service</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
log4j.properties配置文件
代码如下(示例):
log4j.rootCategory=INFO,stdout,info,error
log4j.rootLooger=warn,stdout,info,error
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
log4j.logger.info=info
log4j.appender.info=org.apache.log4j.DailyRollingFileAppender
log4j.appender.info.layout=org.apache.log4j.PatternLayout
log4j.appender.info.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
log4j.appender.info.Threshold=INFO
log4j.appender.info.append=true
log4j.appender.info.File=/Users/xiejc/IdeaProjects/logs/log_info_
log4j.appender.info.DatePattern=yyyy.MM-dd'.log'
log4j.logger.error=error
log4j.appender.error=org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.layout=org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
log4j.appender.error.Threshold=ERROR
log4j.appender.error.append=true
log4j.appender.error.File=/Users/xiejc/IdeaProjects/logs/log_error_
log4j.appender.error.DatePattern=yyyy.MM-dd'.log'
log4j.appender.file.layout=org.apache.log4j.PatternLayout
application.properties配置文件
代码如下(示例):
#端口
server.port=80
# thymeleaf配置
spring.thymeleaf.cache=false
spring.thymeleaf.encoding=utf-8
spring.thymeleaf.mode=HTML5
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
LaunchBrowserController
代码如下(示例):
package com.luckyun.routing.controller;
import com.luckyun.routing.utils.ReadPropertiesUtils;
import com.luckyun.routing.utils.Registery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Properties;
/**
* <p>Title:LaunchBrowserController</p>
*
* @description: 启动谷歌浏览器
* @author: ywj
* @create: 2020-08-30 15:55
*/
@RestController
@EnableAutoConfiguration
public class LaunchBrowserController {
private static final Logger logger = (Logger) LoggerFactory.getLogger(LaunchBrowserController.class);
/**
*
*@Description:从IE浏览器跳转至谷歌浏览器接口
*@Author: ywj
*@Param:
*@Return:
*@Date: 2020/9/3 17:24
**/
@RequestMapping(value = "")
public ModelAndView redirect(Model model,HttpServletRequest request){
String url = "";
String path ="C:\\luckyun\\chrome.exe";
try {
//获得url后面的参数串
String queryString = request.getQueryString();
Map<String, String> readProperties = ReadPropertiesUtils.getProperties();
if (readProperties != null && !StringUtils.isEmpty(readProperties.get("url"))){
url = readProperties.get("url");
}
if (StringUtils.isEmpty(url)){
return new ModelAndView("help","",model);
}else {
url = url.concat("?").concat(queryString);
//String path = Registery.getBrowserExePath();
if (!StringUtils.isEmpty(url) && !StringUtils.isEmpty(path)){
ProcessBuilder proc = new ProcessBuilder(path, url);
proc.start();
}
}
}catch (Exception e){
logger.error("启动谷歌浏览器异常!",e.getMessage());
}
return null;
}
/**
*
*@Description: 获取操作系统信息
*@Author: ywj
*@Param: []
*@Return: java.lang.String
*@Date: 2020/9/2 9:10
**/
@RequestMapping(value = "/getSystemName")
public String getSystemName(){
String systemInfo = "";
try {
Properties pop = System.getProperties(); //获取当前的系统属性集
systemInfo = systemInfo.concat("操作系统的名称:").concat(pop.getProperty("os.name")).concat(" ")
.concat("操作系统的版本:").concat(pop.getProperty("os.version")).concat(" ")
.concat("操作系统的架构:").concat(pop.getProperty("os.arch"));
}catch (Exception e){
logger.error("获取操作系统信息异常",e.getMessage());
}
return systemInfo;
}
}
二、exe4j打包SpringBoot项目的jar包
1.准备所需要的jar、图标、jre等文件
2.保证jar可以运行
3.exe4j打包jar
1.输入软件许可
2.选择JAR in EXE mode,点击下一步
3.输入程序名称和结果输出路径
4.输入exe类型、名称以及相关配置
5.点击Advanced Options配置exe的日志以及是windows系统环境下32位的还是64位的exe程序(其余的配置我这里选择了默认)。
6.配置JAVA的exe的jar包
7.配置JAVA的exe的主函数
注意:这里有一个坑,你需要去jar包里去查看你的Main函数具体是什么,这里并非是springboot的启动类
选择对应的启动类,点击下一步
8.配置JRE的最低和最高版本
9.点击Advanced Options配置exe的jre环境。
注意:这里有一个坑,选择jre的时候必须选择其根目录,我这边选择其他目录打包结果运行不了。
10.选择VM,这里选择Client hotspot VM
11.一直选择默认到最后
12.运行结果
三、Inno Setup 编译器打包exe4j打包的exe,并将谷歌浏览器作为运行环境打包,制作成windows环境下有安装向导的exe程序
1.准备系统在谷歌浏览器需要跳转url的application.properties配置文件
2.准备对应windows版本谷歌浏览器的运行环境,并将谷歌浏览器运行环境全部拷贝到exe4j打包导出的文件夹中
2.Inno Setup 编译器打包
1.创建一个新的脚本文件
2.点击下一步
3.输入程序名称和版本,点击下一步
4.选择应用程序目标基本文件夹和应用程序文件夹名称(这个路径就是在程序安装时选择将程序所需要的运行环境文件放在哪个目录下面)。
5.选择我们用exe4j打包的Test.exe作为应用程序主执行文件。
6.选择添加文件夹将第一步准备的所有支撑运行环境全部放入进来。
注意:这里有一个坑,这里必须将exe4j打包的相关文件以及我们准备的jre、谷歌浏览器全部放入到一个文件夹下,并且在选择的时候选择根目录,将所有文件都加入进来后打包的程序才可以运行,不然会报No JVM could be found on your system.Please define EXE4J_JAVA_HOME.和无法打开谷歌浏览器
7.点击下一步
7.这里可以选择添加许可文件之类的,我这里就不在添加了,点击下一步
8.选择安装包安装的时候指定语言,这里默认中文简体
9.这里选择程序打包完成后导出到哪个目录、程序的名称以及我们之前准备的程序图标文件,点击下一步。
10.点击下一步
11.点击完成
12.如果你对程序仅仅安装上,到这一步选择”是“,然后选择否就可以得到有安装向导的exe程序。
注意:仅仅到这一步对于程序来说是不完整的,我们还需要设置其他的。下面是我们可能需要遇到的几种情况:
1.当程序卸载的时候,我们需要删除程序安装时所产生的文件以及windows环境下开始菜单里面和桌面的快捷方式菜单。
2.当我们重新安装同一个程序的时候,正常的逻辑应该是先停掉windows环境下程序的进程,然后删除程序安装时所产生的文件以及windows环境下开始菜单里面和桌面的快捷方式菜单,最后才开始安装。
3.当我们希望用户在电脑开机后该程序直接自动启动,这里也是可以配置的。
4.当我们不希望用户修改我们程序的默认安装路径,我们这里也可以设置,这样用户在安装的时候安装向导就会跳过让用户选择安装目录这一个选项。
这些配置我已经在第13步以注释的形式放置好,大家可以参考。
13.程序功能的完善配置
;禁止用户选择安装目录,安装向导会自动跳过让用户选择将程序安装到哪个目录
DisableDirPage=yes
;生成我们之前在springboot项目中需要跳转url的配置文件,这里的G:\WinXP\application.properties路径是我们前期所准备并放到打包目录里的文件
Source: "G:\WinXP\application.properties"; DestDir:"{app}"; Flags: ignoreversion
;写入windows注册机并实现程序开机自启
[Registry]
Root: HKLM; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; ValueName: "testrun"; ValueData: "{app}\{#MyAppExeName}"
以下是程序卸载以及重新安装时所需要的配置
; 自定义不同语言文本
[CustomMessages]
;english.checkSoftTip=Setup detects that the software to be installed is running!%n%nClick "ok" to continue the operation after terminating the software, otherwise click "cancel" .
chinesesimp.checkSoftTip=安装程序检测到将安装的软件正在运行!%n%n点击"确定"终止软件后继续操作,否则点击"取消"。
[Code]
// 自定义函数,判断软件是否运行,参数为需要判断的软件的exe名称
function KDetectSoft(strExeName: String): Boolean;
// 变量定义
var ErrorCode: Integer;
var bRes: Boolean;
var strFileContent: AnsiString;
var strTmpPath: String; // 临时目录
var strTmpFile: String; // 临时文件,保存查找软件数据结果
var strCmdFind: String; // 查找软件命令
var strCmdKill: String; // 终止软件命令
begin
strTmpPath := GetTempDir();
strTmpFile := Format('%sfindSoftRes.txt', [strTmpPath]);
strCmdFind := Format('/c tasklist /nh|find /c /i "%s" > "%s"', [strExeName, strTmpFile]);
strCmdKill := Format('/c taskkill /f /t /im %s', [strExeName]);
//ShellExec('open', ExpandConstant('{cmd}'), '/c taskkill /f /t /im 你的软件名.exe', '', SW_HIDE, ewNoWait, ErrorCode);
//bRes := ShellExec('open', ExpandConstant('{cmd}'), '/c tasklist /nh|find /c /i "你的软件名.exe" > 0.txt', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
bRes := ShellExec('open', ExpandConstant('{cmd}'), strCmdFind, '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
if bRes then begin
bRes := LoadStringFromFile(strTmpFile, strFileContent);
strFileContent := Trim(strFileContent);
if bRes then begin
if StrToInt(strFileContent) > 0 then begin
if MsgBox(ExpandConstant('{cm:checkSoftTip}'), mbConfirmation, MB_OKCANCEL) = IDOK then begin
// 终止程序
ShellExec('open', ExpandConstant('{cmd}'), strCmdKill, '', SW_HIDE, ewNoWait, ErrorCode);
Result:= true;// 继续安装
end else begin
Result:= false;// 安装程序退出
Exit;
end;
end else begin
//MsgBox('软件没在运行', mbInformation, MB_OK);
Result:= true;
Exit;
end;
end;
end;
Result :=true;
end;
// 开始页下一步时判断软件是否运行
function NextButtonClick(CurPageID: Integer): Boolean;
begin
if 1=CurPageID then begin
Result := KDetectSoft('{#MyAppExeName}');
Exit;
end;
Result:= true;
end;
// 卸载时关闭软件
function InitializeUninstall(): Boolean;
begin
Result := KDetectSoft('{#MyAppExeName}');
end;
//卸载已经安装的目录
function InitializeSetup(): boolean;
var
ResultStr: String;
ResultCode: Integer;
begin
if RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{577CAA0D-52AF-4B54-8492-E41016DB430A}_is1', 'UninstallString', ResultStr) then
begin
ResultStr := RemoveQuotes(ResultStr);
Exec(ResultStr, '/silent', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
end;
result := true;
end;
注意:这里有个坑,if RegQueryStringValue(HKLM, ‘SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall{577CAA0D-52AF-4B54-8492-E41016DB430A}_is1’, ‘UninstallString’, ResultStr) 这个语句中的“577CAA0D-52AF-4B54-8492-E41016DB430A”是程序的id,你需要修改成你自己的id。id的查看查看方式如下:
14.以下是我的一个完整配置,仅供参考
; 脚本由 Inno Setup 脚本向导 生成!
; 有关创建 Inno Setup 脚本文件的详细资料请查阅帮助文档!
#define MyAppName "Test"
#define MyAppVersion "1.0"
#define MyAppPublisher "我的公司"
#define MyAppURL "http://www.example.com/"
#define MyAppExeName "Test.exe"
[Setup]
; 注: AppId的值为单独标识该应用程序。
; 不要为其他安装程序使用相同的AppId值。
; (生成新的GUID,点击 工具|在IDE中生成GUID。)
AppId={{A0D56786-694D-43F7-8CBD-98A8E5B0659F}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName=C:\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputDir=G:\Test
OutputBaseFilename=TestSetup
SetupIconFile=G:\Test\favicon.ico
Compression=lzma
SolidCompression=yes
;禁止用户选择安装目录,安装向导会自动跳过让用户选择将程序安装到哪个目录
DisableDirPage=yes
[Languages]
Name: "chinesesimp"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
[Files]
Source: "G:\Test\Test.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "G:\Test\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
;生成我们之前在springboot项目中需要跳转url的配置文件,这里的G:\WinXP\application.properties路径是我们前期所准备并放到打包目录里的文件
Source: "G:\WinXP\application.properties"; DestDir:"{app}"; Flags: ignoreversion
; 注意: 不要在任何共享系统文件上使用“Flags: ignoreversion”
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
;写入windows注册机并实现程序开机自启
[Registry]
Root: HKLM; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; ValueName: "testrun"; ValueData: "{app}\{#MyAppExeName}"
; 自定义不同语言文本
[CustomMessages]
;english.checkSoftTip=Setup detects that the software to be installed is running!%n%nClick "ok" to continue the operation after terminating the software, otherwise click "cancel" .
chinesesimp.checkSoftTip=安装程序检测到将安装的软件正在运行!%n%n点击"确定"终止软件后继续操作,否则点击"取消"。
[Code]
// 自定义函数,判断软件是否运行,参数为需要判断的软件的exe名称
function KDetectSoft(strExeName: String): Boolean;
// 变量定义
var ErrorCode: Integer;
var bRes: Boolean;
var strFileContent: AnsiString;
var strTmpPath: String; // 临时目录
var strTmpFile: String; // 临时文件,保存查找软件数据结果
var strCmdFind: String; // 查找软件命令
var strCmdKill: String; // 终止软件命令
begin
strTmpPath := GetTempDir();
strTmpFile := Format('%sfindSoftRes.txt', [strTmpPath]);
strCmdFind := Format('/c tasklist /nh|find /c /i "%s" > "%s"', [strExeName, strTmpFile]);
strCmdKill := Format('/c taskkill /f /t /im %s', [strExeName]);
//ShellExec('open', ExpandConstant('{cmd}'), '/c taskkill /f /t /im 你的软件名.exe', '', SW_HIDE, ewNoWait, ErrorCode);
//bRes := ShellExec('open', ExpandConstant('{cmd}'), '/c tasklist /nh|find /c /i "你的软件名.exe" > 0.txt', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
bRes := ShellExec('open', ExpandConstant('{cmd}'), strCmdFind, '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
if bRes then begin
bRes := LoadStringFromFile(strTmpFile, strFileContent);
strFileContent := Trim(strFileContent);
if bRes then begin
if StrToInt(strFileContent) > 0 then begin
if MsgBox(ExpandConstant('{cm:checkSoftTip}'), mbConfirmation, MB_OKCANCEL) = IDOK then begin
// 终止程序
ShellExec('open', ExpandConstant('{cmd}'), strCmdKill, '', SW_HIDE, ewNoWait, ErrorCode);
Result:= true;// 继续安装
end else begin
Result:= false;// 安装程序退出
Exit;
end;
end else begin
//MsgBox('软件没在运行', mbInformation, MB_OK);
Result:= true;
Exit;
end;
end;
end;
Result :=true;
end;
// 开始页下一步时判断软件是否运行
function NextButtonClick(CurPageID: Integer): Boolean;
begin
if 1=CurPageID then begin
Result := KDetectSoft('{#MyAppExeName}');
Exit;
end;
Result:= true;
end;
// 卸载时关闭软件
function InitializeUninstall(): Boolean;
begin
Result := KDetectSoft('{#MyAppExeName}');
end;
//卸载已经安装的目录
function InitializeSetup(): boolean;
var
ResultStr: String;
ResultCode: Integer;
begin
if RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{577CAA0D-52AF-4B54-8492-E41016DB430A}_is1', 'UninstallString', ResultStr) then
begin
ResultStr := RemoveQuotes(ResultStr);
Exec(ResultStr, '/silent', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
end;
result := true;
end;
这里附上我用的exe4j所用的版本和inno Steup所用的版本
exe4j:链接:https://pan.baidu.com/s/1MInQiCh9COoEEzYbVy7lfw
提取码:s0e4
inno Steup:链接:https://pan.baidu.com/s/1jnPXUbamSJAO4MqjJbDjSA
提取码:vfc6
谷歌浏览器windows的64位版本和32位版本的运行环境
谷歌浏览器:链接:https://pan.baidu.com/s/1KL–oswVwxs4Q7Cv0j2zgw
提取码:fkt5