程序代码
问: 我想让软件安装在windows2000以上的版本, 98,ME的不要.
请问如何在安装的时候得到当前操作系统的信息,如果系统不符合要求,就退出安装程序.
答: ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
strcmp $0 "" 98 nt
98:
messagebox MB_ICONINFORMATION|MB_OK "您使用的操作系统版本过低,无法安装,程序将退出!"
quit
nt:
程序代码
问:我在做一系统补丁,作封装系统时用的,想完成后自动删除自己,以免留下垃圾文件,如何在结束时删除自己呢?
答:System::Call 'kernel32::GetModuleFileNameA(i 0, t .s, i ${NSIS_MAX_STRLEN}) i'
Pop $0
Delete /REBOOTOK $0
程序代码
问:!define MUI_WELCOMEPAGE_TITLE "欢迎使用 ****升级向导"
我想把第一个welcome界面的文字改变
可是,这个定义的改变,是需要我判的,如果是升级,我才重定义文字
我把这个!define是写再.OnInit里面的,可是没起作用啊
答:带 ! 的都是编译期指令,编译好之后就不能改了。
但是你自己追查一下就很容易发现 NSIS\Contrib\Modern UI\System.nsh 里的宏是怎么写的,查找
MUI_WELCOMEPAGE_TITLE 几次就会发现的,其实就是向 $PLUGINSDIR\ioSpecial.ini 里写了一个字串而已。
程序代码
问:我想把安装结束后的“查看自述”改成欣赏音乐但不知道怎么修改代码。
答:!define MUI_FINISHPAGE_SHOWREADME_FUNCTION playmusic
!define MUI_FINISHPAGE_SHOWREADME_TEXT 欣赏音乐
…………
Function playmusic
ExecShell "open" "$INSTDIR\你的音乐文件"
FunctionEnd
程序代码
问:假如我想直接解压一个文件到一个指定的路径,如 d:\temp\aa\ 下,应如何写代码?
答:CreateDirectory "d:\temp\aa\"
File /oname="$PLUGINSDIR\unrar.exe" "WinRAR的安装目录\unrar.exe"
File /oname="$PLUGINSDIR\abc.rar" "要解压的文件"
nsExec::Exec '"$PLUGINSDIR\unrar.exe" x "$PLUGINSDIR\abc.rar" "d:\temp\aa\"'
程序代码
问:在向一个文件写入 ASCII 码时不能继续编译,脚本中不能有 ASCII 码。提示:“错误: 未终结的字符串解析在。。。”
答:字符串要以 " 开头,并以 " 结尾。
问:问题不在于“"”,而在于这个字符“ ”,这个字符只要在脚本中就不能编译。这个字符的二进制是:00011010 十进制:026 十六进制:1A
答:确实如此,那你用 IntFmt 吧,相当于 printf
StrCpy $0 "1234"
IntFmt $1 "%c" 0x1A
StrCpy $0 "$0$16789"
DetailPrint $0
问:终于写入成功了,我用: IntFmt $1 "%c" 032 得到了我想要的字符,但数字字串为什么不是 026 呢?不解。
答:十六进制啊,%c 表示转换为字符。
程序代码
问:在NSIS中如何实现对操作系统的判断呢?
答:System::Call "Kernel32::GetVersion(v) i .s"
Pop $0
IntOp $1 $0 & 0xFF
DetailPrint "Windows 主版本: $1"
IntOp $1 $0 & 0xFFFF
IntOp $1 $1 >> 8
DetailPrint "Windows 次版本: $1"
IntCmpU $0 0x80000000 0 nt
DetailPrint "Windows 95/98/Me"
Goto wend
nt:
DetailPrint "Windows NT/2000/XP"
wend:
程序代码
问:怎样才可以在安装过程中判断目标文件或目录是否存在?
答:Iffilexist "$PROGRAMFILES\123\ABC.EXE" 0 +3
MessageBox MB_OK "存在"
goto +2
MessageBox MB_OK "不存在"
程序代码
问:怎样才可以在安装过程中判断目标注册表的一个值或字段是否存在?
答:ClearErrors
ReadRegstr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" "ABC"
IfErrors 0 +3
MessageBox MB_OK "不存在"
goto +2
MessageBox MB_OK "存在"
程序代码
问:如何获取代表当前系统盘根目录的盘符?
答:Strcpy $R1 $WINDIR 3
问: 如图所示的地方,现在显示的是“setup 将安装...”,除了用自定义字串来修改这个地方以外,如何把这个setup搞成其他的?比如“安装程序现在将...”
答: DirText "安装程序将安装 $(^NameDA) 在下列文件夹。要安装到不同文件夹,单击 [浏览(B)] 并选择其他的文件夹。 $_CLICK"
附图:
问:如何定义欢迎页面的标题字体大小。如下图所示,图三红色框内的标题字体。
答: 使用以下脚本
!define MUI_PAGE_CUSTOMFUNCTION_SHOW ChageFONT
!insertmacro MUI_PAGE_WELCOME
Function ChageFONT
GetDlgItem $0 $MUI_HWND 1201
createFont $1 "Tahoma" "11" "700"
SendMessage $0 ${WM_SETFONT} $1 0
FunctionEnd
附图:
问: 添加版本号
VIProductVersion "1.2.3.4"
VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "Test Application"
VIAddVersionKey /LANG=${LANG_ENGLISH} "Comments" "A test comment"
VIAddVersionKey /LANG=${LANG_ENGLISH} "CompanyName" "Fake company"
VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalTrademarks" "Test Application is a trademark of Fake company"
VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalCopyright" "?Fake company"
VIAddVersionKey /LANG=${LANG_ENGLISH} "FileDescription" "Test Application"
VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "1.2.3"
在脚本中加入上面的代码,则为 NSIS 生成的 exe 添加版本信息。
问题就是,能否让属性中语言显示为“中文(中国)”?如附图1
答: 中文 ID 是 2052。 把 ${LANG_ENGLISH} 改为 2052。
问: 用 2052 之后确实变成“中文(中国)”了。但其他内容仍旧是乱码,不知有什么办法可以解决吗?如附图2
答: 版本信息设置语句,放在 !insertmacro MUI_LANGUAGE 的后面,NSIS 要注重次序的。如果使用古典界面,放在
LoadLanguageFile "${NSISDIR}\Contrib\Language files\SimpChinese.nlf"
的后面。
附图:
问: 如何禁止显示如附图中的 banner 。
答: 图示的效果是因为安装程序初始化的时候,也就是 .onInit 函数里需要用到某个文件的时候安装程序需要搜索整个数据区块来把它解压出来,当安装程序比较大的时候搜索比较费时,这个时候才显示解压百分比。一般都是用 ReserveFile 来避开这种搜索。
比如 Function .onInit 里有
InitPluginsDir
File "/oname=$PLUGINSDIR\io.ini" ".\io.ini"
或者其他类似的话,安装程序就需要搜索并解压这个文件
一般在脚本头部加
ReserveFile ".\io.ini"
这样 io.ini 就保存在数据区块的尾部,安装程序初始化的时候就不用搜索整个数据区块了,相当于加快了安装程序的启动速度。
问:根据以上方法使用了,确实不会再出现初始化的对话框了,但是在自定义的 InstallOptions 页显示前,程序还是会停顿一段时间,请问这是为何?如何避免?
答: 某些控件比较消耗时间的,比如显示 ICON、位图 等,如果 InstallOptions 里含有这些控件可能会停顿。如果
InstallOptions 是第一个页面的话还要把 InstallOptions.dll 加入到 ReserveFile
参数里。再或者就是进入 InstallOptions 的时候含有比较复杂的指令,比如循环等。
一般在加入ReserveFile ${NSISDIR}\Plugins\InstallOptions.dll 既可避免。
附图:
问: 如何运行一个安装文件 .inf
答: ExecWait "RunDll32 advpack.dll,LaunchINFSection skins.inf,DefaultInstall"
问: 关联文件图标后,图标没变化。
答: 刷新图标用, System::Call 'shell32.dll::SHChangeNotify(l, l, i, i) v (0x08000000, 0, 0, 0)'
问:我用NSIS做好了一个安装程序,因为数据较多,一共有400多M,用的LZMA压缩方式,做好后的安装程序约200M,但是我发现在运行这
个安装程序时会在系统TEMP目录产生一个同安装后的全部内容同样大的临时文件(一边运行一边加大,最后到400多M去了),如果我做的程序小倒没什么,
可是这个程序有400多M,除了要写入安装的数据外还要同样大小的空间放临时文件,这样子也实在是太花不来,
我想请问:有什么办法能让其在安装时不使用这么多的临时空间吗?安装的脚本是用HM NIS Edit的向导生成的。
答: 这是因为 NSIS 在用 LZMA
时采用了固实压缩,何谓固实压缩,其实就是把所有文件统一起来压缩,所以这样压出来的文件更加的小,同时也带来了一个问题,安装解压的时候,在临时文件夹
中生成一个临时文件,随着安装的进程逐渐增大,到最后,需要临时文件会变成跟原安装程序一样大,也就是说,需要原安装程序 2
倍的空间才可以安装这个程序,所以对于安装大量文件时,这是不适合的。
NSIS 2.07 版本之前 LZMA 算法是固实压缩的,没有非固实的选项,如果需要这样做,只有下载非固实压缩的编译器,但是 2.07
后的 NSIS 的 LZMA 压缩已经改为默认非固实压缩了,所以这个问题同时也不再存在。如果在制作少量文件的安装时,仍然想取用固实压缩可以加入
/SOLID 参数。像这样: SetCompressor /SOLID lzma
问: 能不能在 Section 区段中实现读取INI文件状态来安装。
如图所示,若选中单选框1则安装1中定义的文件。若不选中则不安装。若选中单选框2则安装2定义的文件。若不选则不安装。
答: 使用以下代码,
!include LogicLib.nsh
Section -post
SetOutPath $INSTDIR
!insertmacro MUI_INSTALLOPTIONS_READ $INI_VALUE "info.ini" "Field 2" "State"
${If} $INI_VALUE = 1
File /a ".\file\fileA.exe"
File /a ".\file\fileB.exe"
${EndIf}
!insertmacro MUI_INSTALLOPTIONS_READ $INI_VALUE "info.ini" "Field 3" "State"
${If} $INI_VALUE = 1
File /a ".\file\fileA.exe"
${EndIf}
SectionEnd
或者使用以下代码,
!include LogicLib.nsh
Section -post
SetOutPath $INSTDIR
!insertmacro MUI_INSTALLOPTIONS_READ $INI_VALUE "info.ini" "Field 2" "State"
${If} $INI_VALUE = 1
;选中时执行的代码
File /a ".\file\fileA.exe"
File /a ".\file\fileB.exe"
${Else}
;不选中时执行的代码
File /a ".\file\fileA.exe"
${EndIf}
SectionEnd
附图:
问: 在 NSIS 中如何设置工作目录,例如一些文件的快捷方式,还有安装完一个软件后运行一个程序,而这个程序需要检测当前工作目录下的某个文件,这时候设置工作目录尤为重要,否则程序不能正常运行。
答: NSIS 中设定工作目录使用 SetOutPath,例如在运行程序的代码 ExecWait
"$INSTDIR\test2.exe" 前放入 SetOutPath $INSTDIR,那么 $INSTDIR
将会成为当前的工作目录,建立快捷方式也会把工作目录设为 $INSTDIR。
卸载之前运行某程序只需要把运行指令放到 Function un.onInit 里就行
问:记得以前看到有帖子介绍过可在NSIS中调用.inf文件安装附加驱动程序,具体实现代码如下形式:
ExecWait "RunDll32 advpack.dll,LaunchINFSection drivers.inf,DefaultInstall"
偶在打包一小东东时使用了这一方法,但遇到的问题时,如果在卸载区段里设置能自动卸载安装过的驱动程序呢?
答: 能否卸载需要看 INF 文件里面是否有卸载的区段,例如使用 NSIS 卸载 Windows Messenger 可以这样:
ExecWait "RunDll32 advpack.dll,LaunchINFSection $windir\INF\msmsgs.inf,BLC.Remove"
关于 BLC.Remove 的来源,可以打开 msmsgs.inf 文件后,能找到名称为 BLC.Remove 的区段,该区段用于卸载。区段的名称是编写者自己定制的。不同的inf文件,区段名也可能不同。
其他的 *.inf 文件也可以按照此类做法。
问: 1. 我做了一个可同时在简繁英下执行的安装程序。但有个很大的困惑。
刚开始时做的是简体中文版,在简中下当然没问题,但在英/繁下,创建的中文程序组名和写注册表时显示的是乱码。于是想到写一个三者皆适合的安装程序。
我的做法是这样的,在涉及到创建中文程序组和写注册表时,加入一个判断,如果英文或繁体,则分别创建英文文件名和big5内码文件名。但在繁体
winxp和英文win2k下测试后,发现根本无法正常创建程序组,也无法正常生成uninstall.exe文件。而写入注册表的中文字符,也不能在繁
体系统的注册表中正常显示,而是乱码。
请教高手,这种多语言环境下该怎么处理,才能正常显示呢?总不能全部都给创建成英文的吧?
2. 另外有个小问题,如何让nsis做的安装程序不显示具体的安装文件名,而只显示“正在复制文件……”? 象foobar那样,可惜foobar也有个显示详细情况的按钮,我想在复制文件过程中完全不显示和提示被复制的文件情况。
答: 1. 最简单的处理办法就是给需要处理的资源进行一个定义,然后使用 LangString 定义不同的资源。给个示例:
Caption "$(CAPTION)"
LangString CAPTION ${1033} "DreamMail Installation"
LangString CAPTION ${2052} "DreamMail 安装向导"
LangString CAPTION ${1028} "DreamMail w杆翾旧"
2. 可以使用 DetailPrint ,示例,
DetailPrint "正在复制文件..."
问: NSIS对于安装卸载的ICO图标大小有什么要求?编译的时候出现以下错误提示,
Error finding icon resources: installer, uninstaller icon size
mismatch - see the Icon instruction's documentation for more information
-- failing!
答: 只要保证安装图标与卸载图标大小相同即可。
问: 如何屏蔽如下图中的安装程序校验。
答: CRCCheck on|off|force
指定安装前安装程序是否对自身执行一个 CRC。注意,如果用户使用了 /NCRC 命令行参数,且你没有指定 force 参数时,不会执行 CRC,这样有可能导致用户安装一个损坏的安装程序。
安装程序 CRC 校验是默认打开的。可以在脚本中用 CRCCheck off 来默认禁止安装程序的 CRC 校验。不过这样做正如解释上说的可能安装会出现问题。作汉化的最好加上校验,免得安装程序的问题变成你汉化质量的问题。
附图:
问:在安装的时候不是可以选择多种语言么?但是我怎样实现当选择英文时就装英文版,选择中文时就装中文版?
答: 使用以下脚本,
StrCmp $LANGUAGE ${LANG_SIMPCHINESE} 0 +3
File "你需要安装的中文文件"
Goto lbl_finish
File "你需要安装的英文文件"
lbl_finish:
问: 组件A 组件B 组件C 均为可选,A可单独安装,B或者C被选择的时候A必须被选择
答: 以下代码,
Section "组件 A" aaa
detailprint "A"
SectionEnd
Section "组件 B" bbb
detailprint "B"
SectionEnd
Section "组件 C" ccc
detailprint "C"
SectionEnd
Function .onSelChange
SectionGetFlags ${bbb} $0
SectionGetFlags ${ccc} $1
IntOp $0 $0 & 1
IntOp $1 $1 & 1
IntCmp $0 1 0 +2
SectionSetFlags ${aaa} 1
IntCmp $1 1 0 +2
SectionSetFlags ${aaa} 1
FunctionEnd
解释:SectionGetFlags 表示获取某区段的flags状态(就是是否被勾选,选中返回值为1,反之为0)
SectionGetFlags ${bbb} $0 表示获取序号为${bbb}的区段的Flags状态并把返回值输出到变量 $0,C 区段相同。
接着就是 StrCmp ,解释同上楼。
SectionSetFlags ${aaa} 1 表示设置序号为 ${aaa} 区段的 Flags 状态为 1,即勾选。
问: 如果是这样写的时候就可以在左边显示页眉位图
!define MUI_ABORTWARNING
!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP "f:\11.bmp"
会显示如附图1。会靠左,但是如果把 MUI_HEADERIMAGE 换成 MUI_HEADERIMAGE_RIGHT 就无法显示位图,只能出现安装图标了,如附图2。
答: 把插入的headerimage图片放到右边(默认是在左边)
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_RIGHT
!define MUI_HEADERIMAGE_BITMAP "include\resource\modern-header.bmp"
而不是你所说的修改 !define MUI_HEADERIMAGE,应该是在这句下面添加 !define MUI_HEADERIMAGE_RIGHT
附图1:
附图2:
问: 怎么让 ”许可协议”页面的标题栏,如程序中的“MutliPages 演示”修改为“MutliPages 演示:许可协议”,如附图。
答: 首先创建一个函数,如下。
Function LicensePagePre
SendMessage $HWNDPARENT ${WM_SETTEXT} 0 "STR:我爱你"
FunctionEnd
然后在协议页面句子
!insertmacro MUI_PAGE_LICENSE "c:\path\to\licence\YourSoftwareLicence.txt"
之前加入如下语句
!define MUI_PAGE_CUSTOMFUNCTION_PRE LicensePagePre
附图:
问: 比如,我把 a.exe 用nsis包装好,安装到 c:\helloLib\a.exe,完成后,想把c:\helloLib\添加到 系统环境变量的 path里头,这样,在任何地方输入 a.exe可执行。如何将路径添加到系统环境变量中?
答:以下代码实现:
ReadRegStr $0 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path"
WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" "$0;C:\hellolib"
另类方法一: 写注册表,如
[HKEY_CLASSES_ROOT\Applications\a.exe\shell\open\command]
@="yourpath\a.exe"
另类方法二:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\a.exe]
@="c:\helloLib\a.exe"
问:在NSIS中如何才能做到根据对于注册表键值的判断决定是否写入字串,如果判断出某个key存在,则写入相应的字串,如果不存在,则不写入字
串。例如:我先要判断 “ HKLM
SOFTWARE\nsis”这个key存不存在。如果存在则写入字串“DispName:nsis”,应该是用“WriteRegStr HKLM
"SOFTWARE\nsis" "DispName" "nsis"”。如果不存在这个key,则不写入注册表,继续下面的安装。
答: 以下代码实现,
ReadRegStr $0 HKLM SOFTWARE\nsis ""
IfErrors 0 +2
Goto +2
WriteRegStr HKLM "SOFTWARE\nsis" "DispName" "nsis"
问:如何制作安装包的时候需要调用系统函数来检测当前安装包运行的操作系统的内码页。
答: 以下代码显示系统语言
System::Call "Kernel32::GetSystemDefaultLangID(v ..) i .s"
Pop $0
IntOp $0 $0 & 0xFFFF
MessageBox MB_OK $0
问: 如何用NSIS注册字体?
答: 以下代码,
!include WinMessages.nsh
Section "MainSection" SEC01
File /oname=$FONTS\tahoma.ttf tahoma.ttf
Push "$FONTS\tahoma.ttf"
System::Call "Gdi32::AddFontResource(t s) i .s"
Pop $0
IntCmp $0 0 0 +2 +2
MessageBox MB_OK "注册字体失败"
SendMessage ${HWND_BROADcast} ${WM_FONTCHANGE} 0 0
SectionEnd
问: 如何用 NSIS 安装输入法。
答: 以下代码,
SetOutPath $SYSDIR
File WBIME.ime
Push "五笔输入法"
Push "$SYSDIR\WBIME.ime"
System::Call "Imm32::ImmInstallIME(t s, t s) i .s"
System::Call "Imm32::ImmIsIME(i s) i .s"
Pop $0
IntCmp $0 1 0 +3 +3
MessageBox MB_OK "输入法安装成功"
Goto +2
MessageBox MB_OK "输入法安装失败"