大龙的博客

常用链接

统计

最新评论

NSIS 常用小问题合集

NSIS 常用小问题合集

问: 在安装过程中按“取消”的话,会弹出是否终止安装的确认窗口,请问怎样设置可以让这个窗口不要出现,按“取消”就直接退出呢?

答: !define MUI_ABORTWARNING  把这句去掉就可以了....


问: 如图所示的地方,现在显示的是“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} "FileDescrīption" "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 杆翾旧"
2. 可以使用 DetailPrint ,示例,
  DetailPrint "正在复制文件..."


问: NSIS对于安装卸载的ICO图标大小有什么要求?编译的时候出现以下错误提示,
Error finding icon resources: installer, uninstaller icon size mismatch - see the Icon instructions 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 "输入法安装失败"

posted on 2007-07-02 16:57 大龙 阅读(936) 评论(1)  编辑 收藏 引用

评论

# re: NSIS 常用小问题合集 2013-07-29 11:49 May

请问nsis打好的安装包在安装的时候,提示“不能打开要写入的文件…………”,有文件在被占用,此时怎么在打包的时候做判断并给出可读性强的用户提示??  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理