NSIS调用外部程序的的命令是Exec,比如Exec "notepad", 将启动Windows的默认文本编辑器Notepad。同样的道理可以用"java -jar test.jar"启动test.jar。
Name "Java Launcher"
Caption "Java Launcher"
Icon "Java Launcher.ico"
OutFile "Java Launcher.exe"
SilentInstall silent
AutoCloseWindow true
ShowInstDetails nevershow
Section ""
Exec "java -jar test.jar"
SectionEnd
将上面这段NSIS脚本拷贝到一个nsi文件中,用NSIS编译器编译,将产生Java Launcher.exe。双击Java Launcher.exe将启动同一目录下的test.jar文件,test.jar必须能够用java -jar test.jar启动,也就是说test.jar的manifest的Library和Main-Class都要正确设值好。否则的话,你可以用java -classpath jar1;jar2 main_class来启动。
如何编译NSIS脚本请参看我之前的一篇随笔 安装程序制作系统NSIS(Nullsoft Scriptable Install System)。
上面这个启动器的一个问题是会打开一个控制台窗口,这是因为用了java命令,只要改为javaw就不会出现控制台了。 另外一个问题是不够健壮,只有当java或者javaw命令在当前目录下或者在PATH上,才能正确启动。也许你想带着一个JRE发布你的程序,那么就不能够去启动系统的java命令。下面来加入寻找java命令目录的功能,寻找的顺序为
- 当前目录下的jre子目录, 如果你的发布程序里带了一个jre,优先启动。
- 环境变量JAVA_HOME
指定的目录
- 在注册表中,HKLM\SOFTWARE\JavaSoft\Java Runtime Environment下保存着安装的JRE的目录信息。
- 当前目录和系统环境变量PATH中的目录
脚本
Name "Java Launcher"
Caption "Java Launcher"
Icon "Java Launcher.ico"
OutFile "Java Launcher.exe"
SilentInstall silent
AutoCloseWindow true
ShowInstDetails nevershow
Section ""
Call GetJRE
Pop $R0
; change for your purpose (-jar etc.)
StrCpy $0 '"$R0" -jar test.jar'
SetOutPath $EXEDIR
ExecWait $0
SectionEnd
Function GetJRE
Push $R0
Push $R1
ClearErrors
StrCpy $R0 "$EXEDIR\jre\bin\javaw.exe"
IfFileExists $R0 JreFound
StrCpy $R0 ""
ClearErrors
ReadEnvStr $R0 "JAVA_HOME"
StrCpy $R0 "$R0\bin\javaw.exe"
IfErrors 0 JreFound
ClearErrors
ReadRegStr $R1 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment" "CurrentVersion"
ReadRegStr $R0 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment\$R1" "JavaHome"
StrCpy $R0 "$R0\bin\javaw.exe"
IfErrors 0 JreFound
StrCpy $R0 "javaw.exe"
JreFound:
Pop $R1
Exch $R0
FunctionEnd
Function GetJRE定义了寻找JRE的函数,找到的javaw命令的路径可以从R0中取回。R0,R1是NSIS预定义的寄存器,或者说是变量,Push $R0将R0的内容压进堆栈,Pop $R0从堆栈中取回R0的内容。这一点和汇编程序很像。GetJRE按定义好的顺序判断指定路径下的是否存在javaw,如果是,返回。比如
ReadEnvStr $R0 "JAVA_HOME" 读入JAVA_HOME的值到R0
StrCpy $R0 "$R0\bin\javaw.exe"
加上\bin\javaw.exe
IfFileExists $R0 JreFound
如果R0指定的文件存在,跳转到JreFound
ReadRegStr读取注册表中的键值。Exch $R0交换R0和堆栈头元素的值。其他函数从字面上就可以理解了,不需要过多的解释。
最后要说明的是,这里用Execwait启动java命令,而不是Exec。区别是Exec马上退出Java Launcher.exe的进程,而Execwait不退出,也就是说用Execwait在关闭程序之前,有两个活动进程,Java Launcher.exe和javaw.exe。这正是eclipse3.3之前的EXE启动器的情况,比如Eclipse3.2启动后,任务管理器里有eclipse.exe和javaw.exe两个进程。使用Execwait的原因是Exec在Windows 2000下出现的一个问题,在使用程序的过程中,如果用户改变了桌面属性,比如背景图,系统就挂掉了。Eclipse在3.3之后改成了使用Java的Invocation Interface启动startup.jar。详细的情况请看org.eclipse.equinox.executable项目。
转载请保留
http://www.blogjava.net/xilaile/archive/2007/05/13/117039.html